Laravel modules - php

I came with this modules solution and I was wondering if is anything wrong with it?
composer.json
"autoload" : {
"classmap" : [
"....",
"app/modules"
],
"psr-4" : {
"modules\\" : "app"
}
}
app/config/app.php
'provider' => array(
'....',
'Modules\ServiceProvider\ModulesServiceProvider'
app/modules/ModulesServiceProvider.php
<?php
namespace Modules\ServiceProvider;
use Illuminate\Support\ServiceProvider;
class ModulesServiceProvider extends ServiceProvider
{
public function register() {
$this->app->bind('modules', function()
{
return new Modules;
});
}
public function boot() {
// set modules path
$modules_path = __DIR__ . '/';
// scan modules directory
$modules = scandir($modules_path);
foreach($modules as $module)
{
if($module === '.' || $module === '..') continue;
// check if module exist
if(is_dir($modules_path) . '/' . $module)
{
// set routes.php path
$routes_path = $modules_path . $module . '/routes.php';
// set modules views path
$views_path = $modules_path . $module . '/views';
// if routes.php exists
if(file_exists($routes_path))
{
// required routes.php
\View::addNamespace($module, $views_path);
require_once($routes_path);
}
else
{
// else do ... what ??
continue;
}
}
}
}
}
Everything works fine, I can call the views with View::make('moduleName::viewName'), routes are defined in each module which makes it easier to maintain.
If this ain't a good solution could you please explain?

Here's how i've done it in my package l5-modular:
protected $files;
/**
* Bootstrap the application services.
*
* #return void
*/
public function boot() {
if(is_dir(app_path().'/Modules/')) {
$modules = array_map('class_basename', $this->files->directories(app_path().'/Modules/'));
foreach($modules as $module) {
$routes = app_path().'/Modules/'.$module.'/routes.php';
$views = app_path().'/Modules/'.$module.'/Views';
$trans = app_path().'/Modules/'.$module.'/Translations';
if($this->files->exists($routes)) include $routes;
if($this->files->isDirectory($views)) $this->loadViewsFrom($views, $module);
if($this->files->isDirectory($trans)) $this->loadTranslationsFrom($trans, $module);
}
}
}

Related

Dynamic instantation of namespaced methods in php

There are few routers out there but I decided to create a very simple route for a very light site.
Here is my index.php
$route = new Route();
$route->add('/', 'Home');
$route->add('/about', 'About');
$route->add('/contact', 'Contact');
Here is my router:
<?php namespace Laws\Route;
use Laws\Controller\Home;
class Route
{
private $_uri = array();
private $_method = array();
private $_route;
public function __construct()
{
}
public function add($uri, $method = null)
{
$this->_uri[] = '/' . trim($uri, '/');
if ($method != null) {
$this->_method[] = $method;
}
}
public function submit()
{
$uriGetParam = isset($_GET['uri']) ? '/' . $_GET['uri'] : '/';
foreach ($this->_uri as $key => $value) {
if (preg_match("#^$value$#", $uriGetParam)) {
$useMethod = $this->_method[$key];
new $useMethod(); // this returns an error (cannot find Home'
new Home(); // this actually works.
}
}
}
}
new $useMethod(); does not work. returns error 'cannot find Home'
new Home(); actually works.
What am I missing here?
You can use your concurrent way for calling a class or you can use this:
call_user_func(array($classname,$methodname))

OOP Based config file

I have a config file for my app but I am having trouble passing the object around as I need it to be available to my main index page and parent controller.
Currently I have to pass it as a parameter for the __Construct function in every controller I make, which certainly doesn't seem to be the best way to do it.
index.php
<?PHP
require 'config/conf.php';
$errors = array();
//Memcache the config file at some point.
define('DEBUG_MODE', 0);
define('SITE_KEY', '');
define('ROOT', 'http://manager.com/');
define('Vs', 'views/');
define('Cs', 'controllers/');
function __autoload($className) { // Autoload both controllers and models.
if (stristr($className, 'Model')) {
if (is_readable(Ms . $className . '.php')) {
include Ms . $className . '.php';
}
} else {
if (is_readable(Cs . $className . '.php')) {
include Cs . $className . '.php';
}
}
}
require 'libs/core/Controller.php';
require 'libs/core/View.php';
$Memcache = null;
if ($config['ADDITIONAL_LIBS']['MEMCACHED']) {
if (!class_exists('Memcache')) {
$errors[] = array('code' => 1, 'type' => 'error', 'title' => 'Memcached failed to load', 'msg' => 'Memcached is not installed or initialised properly.');
}
}
if ($config['SESSIONS']) {
require 'libs/core/Session.php';
}
if ($config['DATABASE']) {
define('Ms', 'models/');
require 'libs/core/Database.php';
require 'libs/core/Model.php';
}
if ($config['ADDITIONAL_LIBS']['UTIL']) {
if (file_exists('libs/extra/Util.php')) {
require 'libs/extra/Util.php';
} else {
$errors[] = loadFail('Util');
}
}
if ($config['ADDITIONAL_LIBS']['PBKDF2']) {
if (file_exists('libs/extra/PBKDF2.php')) {
require 'libs/extra/PBKDF2.php';
} else {
$errors[] = loadFail('PBKDF2');
}
}
if ($config['ADDITIONAL_LIBS']['MCAPI']) {
if (file_exists('libs/extra/MCAPI.php')) {
require 'libs/extra/MCAPI.php';
} else {
$errors[] = loadFail('MCAPI');
}
}
require 'libs/core/Router.php';
$Site = new Router($Config, $errors);
function loadFail($moduleName) {
return array('code' => 1, 'type' => 'error', 'title' => $moduleName . ' failed to load', 'msg' => $moduleName . '.php was not found in the "libs/extra/" directory.');
}
My conf file:
$Config = new Config();
$Config->set('HOME_PAGE', 'index');
$Config->set('MEMCACHE_ENABLE', true);
$Config->set('MEMCACHE_SERVERS', array(
array(
'SERVER' => 'localhost',
'PORT' => '11211'
)
));
class Config {
public $params;
function __construct() {
}
public function set($param, $value) {
$this->params[$param] = $value;
}
public function get($param) {
return $this->params[$param];
}
}
And my main controller class which I need the config object to be accesible from:
abstract class Controller {
public $view;
public $Memcache;
public function __construct($Config) {
// Autoload model if it exists...
$model = get_class($this) . 'Model';
if (is_readable(Ms . $model . '.php')) {
if ($Memcache) {
if (!$this->model = $Memcache->get($model)) {
$this->model = new $model;
}
}
}
$this->view = new View();
}
}
What is a slick and clean way to achieve what I want, which is basically to have a centralised configuration file who's parameters are available to both my main index file and parent controller?
Config is typically handled using the Registry pattern:
http://avedo.net/101/the-registry-pattern-and-php/
That's probably the most common/straightfoward way to do it. Some people prefer not to make config quite so global, in which case you would often use the Factory pattern and let the factory inject the config so that you don't have to explicitly do it with each instantiation.

Phalcon loading helper file library

I have created a library that which will load a php file (which may contains users custom functions in it...) you can either call it from bootstrap also from the controller. if file does not exists it will display the error msg. Thing is am i doing it in the currect way?
If i did miss any thing point me out.. Thanks
Helpers is the folder where users can put php files
app/
controllers/
models/
helpers/
library/
views/
In "library/" Folder a php file named "helperfile.php"
class helperfile extends Phalcon\Mvc\User\Component
{
var $helper_Folder = '../app/helpers';
var $files = array();
public function __construct()
{
}
public function initialize()
{
}
public function include_file($files, $run = true)
{
if (!is_array($files))
$files = array($files);
foreach ($files as $file)
$this->files[$file] = $file;
if ($run)
$this->load();
}
public function beforeDispatch()
{
$this->load();
}
private function load()
{
if (empty($this->files))
return false;
foreach ($this->files as $file) {
$file = trim($file) . '.php';
if ($this->is_file_exists($file)) {
require $this->helper_Folder . '/' . $file;
}
}
}
private function is_file_exists($path)
{
$full_path = $this->helper_Folder . '/' . $path;
if (!file_exists($full_path)) {
$this->flash->error("Helper File Missing: " . $full_path);
return false;
}
return true;
}
}
// to auto load file on every page through the bootstrap ("public/index.php")
$di->set('dispatcher', function () {
//Create/Get an EventManager
$eventsManager = new Phalcon\Events\Manager();
/*
* Load Custom function files which are in the helpers folder
*/
$loadHelper = new helperfile();
$loadHelper->include_file([
'calling_from_bootstrap_1',
'calling_from_bootstrap_2'
],false);
$eventsManager->attach('dispatch', $loadHelper);
$dispatcher = new Phalcon\Mvc\Dispatcher();
$dispatcher->setEventsManager($eventsManager);
return $dispatcher;
});
// To load it from controller
$loadHelper = new helperfile();
$loadHelper->include_file([
'calling_from_theController'
]);
That looks like it shoould work, but I think you underestimate the amount of work Phalcon can do for you.
An example of what is in the helper files would be useful. For the sake of this example I will assume that that it is like this:
app/
helpers/
ProductHelper.php
and in ProductHelper.php
class ProductHelper{
// code here
}
In your bootstrap where you have the loader you define your directories
$phalconLoader = new \Phalcon\Loader();
/**
* We're a registering a set of directories taken from the configuration file
*/
$phalconLoader->registerDirs(
array(
$phalconConfig->application->controllersDir,
$phalconConfig->application->modelsDir,
// path to helper dir here
)
)->register();
and then in your controller
public function productAction(){
$productHelper = new productHelper();
}
That should work. It is less code, so is simpler should run a bit faster (using phalcon's built in code rather than writing some php will always be faster)
If the code in the helpers is not in classes, or not named the same as the filename, then it probably should be. Makes things a lot simpler.
Di Enabled Version
class ProductHelper extends \Phalcon\DI\Injectable{
public $config;
public function myFunction(){
$this->config = $this->getDI ()->get ('config');
}
}
and in the controller
public function indexAction()
{
$helper = new ProductHelper();
$helper->setDI($this->getDI());
$helper->myFunction();
}
Alternatively when creating your DI
$di->set ('productHelper', function () use ($config, $di) {
$helper = new ProductHelper();
$helper->setDi ($di);
return $helper;
});
and in the controller
public function indexAction()
{
$helper = new ProductHelper();
$helper->myFunction();
}

Challenging Issue : Loading models from external directory in Code Igniter

I have been trying to figure out a way to load models from different directory other than "application/models" directory.
I want to load my model from "application/modules".
I have tried the instructions by extending CI_Loader by following instructions provided in
http://ellislab.com/forums/viewthread/103276/#
but it is giving me error "Unable to locate the specified class: Model.php" whereas my core "Model.php" is there under "system/core" folder.
Even ,I have also tried to load model using
$this->load->model (APPPATH.'modules/mymodel.php');
but no success.
UPDATE:
I want my model loader to behave like this :
$this->load->module('mymodel')
and
$this->mymodel->mymodelmethod() !!
NOT like: $this->load->models('mymodel')
Is there any way i could load models from outside the "application/modules" folder ?
Please advise .Thanks
The problem is that the code you reference is for an older version of codeigniter. In older versions of codeigniter the CI_Model class was named Model. As the class Model doesn't exist in the latest version of php you are getting the error:
Unable to locate the specified class: Model.php
The part of the code where this is happening is towards the end (line 114):
if ( ! class_exists('Model'))
{
load_class('Model', FALSE);
}
If you check your system/core/Loader.php you will see that in the version of codeigniter you are using this has been replaced with:
if ( ! class_exists('CI_Model'))
{
load_class('Model', 'core');
}
You need to re-write the MY_Loader.php to make it compatible with the version of codeigniter you are using, presumably 2.1.
The best way to do this would be to grab the Codeigniter 2.1 version of the core Loader.php and use the model() method from it as a base for re-writing your MY_Loader.php.
Something to bare in mind when re-writing your MY_Loader.php is that constructors also changed in later versions of codeigniter, so your MY_Loader class should look something like this:
class MY_Loader extends CI_Loader {
function __construct()
{
parent::__construct();
}
public function model($model, $name = '', $db_conn = FALSE)
{
...
}
}
More details on extending core classes can be found in the Codeigniter Documentation
UPDATE
I noticed you changed your functionality, so I updated the answer. You can create a whole new loader and base it off the core CI_Model class, although it seems like a lot of effort when you could just extend the model loader and be done.
class MY_Loader extends CI_Loader {
protected $_ci_module_paths = array();
protected $_ci_modules = array();
function __construct()
{
parent::__construct();
$this->_ci_module_paths = array(APPPATH);
}
public function initialize()
{
$this->_ci_classes = array();
$this->_ci_loaded_files = array();
$this->_ci_models = array();
$this->_ci_modules = array();
$this->_base_classes =& is_loaded();
$this->_ci_autoloader();
return $this;
}
public function module($module, $name = '', $db_conn = FALSE)
{
if (is_array($module))
{
foreach ($module as $babe)
{
$this->$module($babe);
}
return;
}
if ($module == '')
{
return;
}
$path = '';
// Is the $module in a sub-folder? If so, parse out the filename and path.
if (($last_slash = strrpos($module, '/')) !== FALSE)
{
// The path is in front of the last slash
$path = substr($module, 0, $last_slash + 1);
// And the module name behind it
$module = substr($module, $last_slash + 1);
}
if ($name == '')
{
$name = $module;
}
if (in_array($name, $this->_ci_modules, TRUE))
{
return;
}
$CI =& get_instance();
if (isset($CI->$name))
{
show_error('The module name you are loading is the name of a resource that is already being used: '.$name);
}
$module = strtolower($module);
foreach ($this->_ci_module_paths as $mod_path)
{
if ( ! file_exists($mod_path.'modules/'.$path.$module.'.php'))
{
continue;
}
if ($db_conn !== FALSE AND ! class_exists('CI_DB'))
{
if ($db_conn === TRUE)
{
$db_conn = '';
}
$CI->load->database($db_conn, FALSE, TRUE);
}
if ( ! class_exists('CI_Model'))
{
load_class('Model', 'core');
}
require_once($mod_path.'modules/'.$path.$module.'.php');
$module = ucfirst($module);
$CI->$name = new $module();
$this->_ci_modules[] = $name;
return;
}
// couldn't find the model
show_error('Unable to locate the module you have specified: '.$module);
}
public function add_package_path($path, $view_cascade=TRUE)
{
$path = rtrim($path, '/').'/';
array_unshift($this->_ci_library_paths, $path);
array_unshift($this->_ci_model_paths, $path);
array_unshift($this->_ci_module_paths, $path);
array_unshift($this->_ci_helper_paths, $path);
$this->_ci_view_paths = array($path.'views/' => $view_cascade) + $this->_ci_view_paths;
// Add config file path
$config =& $this->_ci_get_component('config');
array_unshift($config->_config_paths, $path);
}
public function remove_package_path($path = '', $remove_config_path = TRUE)
{
$config =& $this->_ci_get_component('config');
if ($path == '')
{
$void = array_shift($this->_ci_library_paths);
$void = array_shift($this->_ci_model_paths);
$void = array_shift($this->_ci_module_paths);
$void = array_shift($this->_ci_helper_paths);
$void = array_shift($this->_ci_view_paths);
$void = array_shift($config->_config_paths);
}
else
{
$path = rtrim($path, '/').'/';
foreach (array('_ci_library_paths', '_ci_model_paths', '_ci_module_paths', '_ci_helper_paths') as $var)
{
if (($key = array_search($path, $this->{$var})) !== FALSE)
{
unset($this->{$var}[$key]);
}
}
if (isset($this->_ci_view_paths[$path.'views/']))
{
unset($this->_ci_view_paths[$path.'views/']);
}
if (($key = array_search($path, $config->_config_paths)) !== FALSE)
{
unset($config->_config_paths[$key]);
}
}
// make sure the application default paths are still in the array
$this->_ci_library_paths = array_unique(array_merge($this->_ci_library_paths, array(APPPATH, BASEPATH)));
$this->_ci_helper_paths = array_unique(array_merge($this->_ci_helper_paths, array(APPPATH, BASEPATH)));
$this->_ci_model_paths = array_unique(array_merge($this->_ci_model_paths, array(APPPATH)));
$this->_ci_module_paths = array_unique(array_merge($this->_ci_module_paths, array(APPPATH)));
$this->_ci_view_paths = array_merge($this->_ci_view_paths, array(APPPATH.'views/' => TRUE));
$config->_config_paths = array_unique(array_merge($config->_config_paths, array(APPPATH)));
}
private function _ci_autoloader()
{
if (defined('ENVIRONMENT') AND file_exists(APPPATH.'config/'.ENVIRONMENT.'/autoload.php'))
{
include(APPPATH.'config/'.ENVIRONMENT.'/autoload.php');
}
else
{
include(APPPATH.'config/autoload.php');
}
if ( ! isset($autoload))
{
return FALSE;
}
// Autoload packages
if (isset($autoload['packages']))
{
foreach ($autoload['packages'] as $package_path)
{
$this->add_package_path($package_path);
}
}
// Load any custom config file
if (count($autoload['config']) > 0)
{
$CI =& get_instance();
foreach ($autoload['config'] as $key => $val)
{
$CI->config->load($val);
}
}
// Autoload helpers and languages
foreach (array('helper', 'language') as $type)
{
if (isset($autoload[$type]) AND count($autoload[$type]) > 0)
{
$this->$type($autoload[$type]);
}
}
// A little tweak to remain backward compatible
// The $autoload['core'] item was deprecated
if ( ! isset($autoload['libraries']) AND isset($autoload['core']))
{
$autoload['libraries'] = $autoload['core'];
}
// Load libraries
if (isset($autoload['libraries']) AND count($autoload['libraries']) > 0)
{
// Load the database driver.
if (in_array('database', $autoload['libraries']))
{
$this->database();
$autoload['libraries'] = array_diff($autoload['libraries'], array('database'));
}
// Load all other libraries
foreach ($autoload['libraries'] as $item)
{
$this->library($item);
}
}
// Autoload models
if (isset($autoload['model']))
{
$this->model($autoload['model']);
}
// Autoload modules
if (isset($autoload['module']))
{
$this->module($autoload['module']);
}
}
}
You can use the above in your controller via:
$this->load->module('test_module');
$this->test_module->method();
If i am getting your problem correctly , you have to initialize the instance of CI.
Example :-
In your external file do this :-
class modules
{
var $CI;
function __construct()
{
$this->CI =& get_instance();
}
function retrieve_data()
{
// Load Model
$this->CI->load->model('YOUR MODEL NAME'); // Give the name of your model that you want to laod
}
}
Hope it helps you :)
As far as i understand your question the answer lies here.
Moduler Extension
download it and install according to the instructions. then you can simply access any thing with these steps.
In your controller load the module like this.
$this->load->module('pages');
Make sure you have a directory Modules under application. And your Module pages should exist there. Pages module can have controller , models , views , helpers , config and libraries etc.
Now you need to call model. Here is how you can do it.
$this->pages->model->test_model->get_test_data();
Also you should note that loading module loads all the resources.
If nothing works, try this
public function setPackagePaths($path, $view_cascade=TRUE, $model_cascade=TRUE, $library_cascade=TRUE, $helper_cascade=TRUE) {
$path = rtrim($path, '/').'/';
///$this->_ci_view_paths = $this->_ci_library_paths = $this->_ci_model_paths = array();
$this->_ci_library_paths = array($path.'libraries/' => $library_cascade) + $this->_ci_library_paths ;
$this->_ci_helper_paths = array($path.'helpers/' => $helper_cascade) + $this->_ci_helper_paths ;
$this->_ci_model_paths = array($path.'models/' => $model_cascade) + $this->_ci_model_paths ;
$this->_ci_view_paths = array($path.'views/' => $view_cascade) + $this->_ci_view_paths;
// Add config file path
$config =& $this->_ci_get_component('config');
array_unshift($config->_config_paths, $path);
}
Its a hardcore way to update this function to Loader Class. But works fine.

Allow SVN commit with existing PreCommit hook warnings

I am using SVN precommit hooks to validate my code standard (PSR2) before being able to commit. This works perfectly with just one exception. My unit test (PHPUnit) files exist of my bootstrap class existing of all static unit test functions, but also enables error messages above the bootstrap class definition.
The PSR2 standard will give a warning when trying to commit this, because you cannot have code that is not in a class or function in a file that contains a class definition.
Does anyone have either a way to exclude this error in my codesniffer or a way to make my code valid (without putting the code to enable my error messages in each static function of the bootstrap class)?
Here's the file:
<?php
namespace AlbumTest;
use Zend\Loader\AutoloaderFactory;
use Zend\Mvc\Service\ServiceManagerConfig;
use Zend\ServiceManager\ServiceManager;
use Zend\Stdlib\ArrayUtils;
use RuntimeException;
error_reporting(E_ALL | E_STRICT);
chdir(__DIR__);
class Bootstrap
{
protected static $serviceManager;
protected static $config;
protected static $bootstrap;
public static function init()
{
// Load the user-defined test configuration file, if it exists; otherwise, load
if (is_readable(__DIR__ . '/TestConfig.php')) {
$testConfig = include __DIR__ . '/TestConfig.php';
} else {
$testConfig = include __DIR__ . '/TestConfig.php.dist';
}
$zf2ModulePaths = array();
if (isset($testConfig['module_listener_options']['module_paths'])) {
$modulePaths = $testConfig['module_listener_options']['module_paths'];
foreach ($modulePaths as $modulePath) {
if (($path = static::findParentPath($modulePath)) ) {
$zf2ModulePaths[] = $path;
}
}
}
$zf2ModulePaths = implode(PATH_SEPARATOR, $zf2ModulePaths) . PATH_SEPARATOR;
$zf2ModulePaths .= getenv('ZF2_MODULES_TEST_PATHS') ?: (defined('ZF2_MODULES_TEST_PATHS')
? ZF2_MODULES_TEST_PATHS : '');
static::initAutoloader();
// use ModuleManager to load this module and it's dependencies
$baseConfig = array(
'module_listener_options' => array(
'module_paths' => explode(PATH_SEPARATOR, $zf2ModulePaths),
),
);
$config = ArrayUtils::merge($baseConfig, $testConfig);
$serviceManager = new ServiceManager(new ServiceManagerConfig());
$serviceManager->setService('ApplicationConfig', $config);
$serviceManager->get('ModuleManager')->loadModules();
static::$serviceManager = $serviceManager;
static::$config = $config;
}
public static function getServiceManager()
{
return static::$serviceManager;
}
public static function getConfig()
{
return static::$config;
}
protected static function initAutoloader()
{
$vendorPath = static::findParentPath('vendor');
if (is_readable($vendorPath . '/autoload.php')) {
$loader = include $vendorPath . '/autoload.php';
} else {
$zf2Path = getenv('ZF2_PATH') ?: (defined('ZF2_PATH')
? ZF2_PATH : (is_dir($vendorPath . '/ZF2/library')
? $vendorPath . '/ZF2/library' : false));
if (!$zf2Path) {
throw new RuntimeException(
'Unable to load ZF2. Run `php composer.phar install` or define a ZF2_PATH environment variable.'
);
}
include $zf2Path . '/Zend/Loader/AutoloaderFactory.php';
}
AutoloaderFactory::factory(
array(
'Zend\Loader\StandardAutoloader' => array(
'autoregister_zf' => true,
'namespaces' => array(
__NAMESPACE__ => __DIR__ . '/' . __NAMESPACE__,
),
),
)
);
}
protected static function findParentPath($path)
{
$dir = __DIR__;
$previousDir = '.';
while (!is_dir($dir . '/' . $path)) {
$dir = dirname($dir);
if ($previousDir === $dir) {
return false;
}
$previousDir = $dir;
}
return $dir . '/' . $path;
}
}
Bootstrap::init();
How does your precommit-hook look like? Could you just remove the first few lines dynamically before sending the to the Codesniffer?
Another solution would be to set the error_reporting in the init of your bootstrap

Categories