I know the multi module application structure of Phalcon, but is it possible to have a nested module structure like following example shows? I want to have a system, where I can hot-plug new sub-modules (for backend, frontend) to the system. Routes, menu entries etc. should get automatically extended when I copy a new module folder into the sub-module folder.
module-backend
controllers
models etc.
sub-modules
forum
controllers
models
etc.
news
controllers
models
etc.
users
controllers
models
etc.
module-frontend
controllers
models
sub-modules
like backend module structure
Is there a way with events to hot-plug such modules to the system?
yes you can. the first solution what i can think of is this:
while registering your loader in index.php:
$loader = new \Phalcon\Loader();
$loader->registerDirs(array(
$config->application->controllersDir,
$config->application->pluginsDir,
));
$loader->registerPrefixes(
array(
"Model_" => $config->application->modelsDir,
)
);
$loader->registerNamespaces(array(
'RemoteApi' => $config->application->librariesDir . 'RemoteApi/'
));
$loader->register();
notice registerPrefixes. you can register different prefix for different models like:
$loader->registerPrefixes(
array(
"FModel_" => $config->application->forumModels,
"NModel_" => $config->application->newsModels,
)
);
you can register prefixes to other things too. I also added this example
$loader->registerNamespaces(array(
'RemoteApi' => $config->application->librariesDir . 'RemoteApi/'
));
this way you can order your stuff under different namespace's.
You can approach my organization structure of modules in the application:
https://github.com/oleksandr-torosh/yona-cms
The modules are presented as separate entities:
https://github.com/oleksandr-torosh/yona-cms/tree/master/app/modules
Index
Page
Projects
Video
Likely for your application you do not need to use the standard multi-modular structure from the box
Related
Good day.
I've just started learning ZF2, replicated the Album example step-by-step, and then decided to make it a bit more interesting by adding user registration, and then make the two work together in some way, so i added a new 'Auth' module.
So, when i only had one module in the module list (aside from the Application module) in application.config.php, it was all fine, but when i added the Auth module to the list like so:
'modules' => array('Application', 'Album','Auth',)
i got the following error when trying to access any views from the album module which was working absolutely fine prior to this change:
Zend\View\Renderer\PhpRenderer::render: Unable to render template "album/album/index"; resolver could not resolve to a file
But when i changed the order in which the modules are presented in this array like so:
'modules' => array('Application', 'Auth','Album',)
not a single view (and it has only one) from the Auth module could be rendered, while the Album module was fine.
Zend\View\Renderer\PhpRenderer::render: Unable to render template "auth/user/index"; resolver could not resolve to a file
Both of these views exist at these locations, but the renderer doesn't see them for some reason.
You can see the project's contents here.
Thank you for any tips in advance.
Looks like you copy pasted the the view manager config for Auth module.config.php.
This should be auth rather than album for your templates to work correctly.
'view_manager' => array(
'template_path_stack' => array(
'auth' => __DIR__ . '/../view',
),
),
I'm currently working on translating an existing Zend Framework 2 project that is spread around multiple modules.
My understanding of the translate functionality of ZF2, is that you can have as many translation files, providing each are 'namespaced' to a different text_domain. This works fine in practice, with each module having the following in their module.config.php file:
...
'translator' => array (
'locale' => 'en_US',
'translation_file_patterns' => array (
array (
'type' => 'phparray',
'base_dir' => __DIR__ . '/../language',
'pattern' => '%s_default.php',
'text_domain' => 'ExampleModule'
),
),
),
...
Which adds a ../language/*_default.php file to the translation list with a text_domain of ExampleModule. All good so far.
Now, the translator itself needs to know which text_domain to pick a translation from and will use default if one isn't provided.
So, inside and at the top of all of my view *.phtml files, I have:
$this->plugin('translate')->setTranslatorTextDomain('ExampleModule');
$this->formLabel()->setTranslatorTextDomain('ExampleModule');
$this->formText()->setTranslatorTextDomain('ExampleModule');
Which tells all proceeding $this->translate() blocks and form elements which text_domain to use.
This is great, and works fine, but it doesn't sit well with the DRY principle in that I have similar code at the top of every view. I attempted to extend the ViewModel class so I can pick a different ViewModel class in the controller and have the above code already baked in, but the plugins aren't available at that stage.
How would I include the above code on every/most views without having to type it each time?
After searching endlessly, I found that the default renderer - PhpRenderer - can be accessed via the onBootstrap method of Module.php (reference).
As the view scripts are rendered by PhpRenderer the $this variable points to PhpRenderer (reference). This means that you can attach the code I needed to Module.php as below:
// Get the default ViewRenderer (PhpRenderer) and setup the correct text domain for derivative plugins
$viewRenderer = $e->getApplication()->getServiceManager()->get('ViewRenderer');
$viewRenderer->plugin('translate')->setTranslatorTextDomain('ExampleModule');
$viewRenderer->formLabel()->setTranslatorTextDomain('ExampleModule');
$viewRenderer->formText()->setTranslatorTextDomain('ExampleModule');
As the current namespace matches the text_domain I need, the above can be simplified by swapping 'ExampleModule' with __NAMESPACE__.
EDIT: If you're looking for a different text_domain per module; you'll need in just one Module.php:
$viewRenderer = $e->getApplication()->getServiceManager()->get('ViewRenderer');
$eventManager->getSharedManager()->attach('Zend\Mvc\Controller\AbstractActionController', 'dispatch', function($e) use ($viewRenderer) {
$controller = $e->getTarget();
$controllerClass = get_class($controller);
$moduleNamespace = substr($controllerClass, 0, strpos($controllerClass, '\\'));
$viewRenderer->plugin('translate')->setTranslatorTextDomain($moduleNamespace);
$viewRenderer->formLabel()->setTranslatorTextDomain($moduleNamespace);
$viewRenderer->formText()->setTranslatorTextDomain($moduleNamespace);
}, 100);
I am looking at a few tutorials and to just create 1 module you have to modify a bunch of configuration files in order to make the controllers, models, and views work. I see this as impossible to try and remember it all or comprehend what it is I’m doing. Is there an alternative method that creates these for me? so that i don’t have to write it all out every time i create a controller, or a module etc. I honestly don’t see how this is faster. I come from a codeigniter background so making this switch has me banging my head against the wall multiple times trying to comprehend.
I've been using ZF2 for a few months now, and I've found that writing a class to generate that config for you is helpful.
There is no tool out there to do that for you. But if you follow the following approach, you should come right quite quickly:
class Configurator {
public static function route($name, $url, $controller, $action='index') {
return array(
'router' => array(
...
),
);
}
# Other static configuring methods
...
}
Then in your config you use the Configurator like this:
use Configurator;
return array_merge_recursive(
array(
'view_manager' => array(
...
),
),
# Other top-level config
...
Configurator::route('home', '/', 'Application\Controller\Index'),
Configurator::route('other', '/other', 'Application\Controller\Other')
);
Your config is deep-merged by array_merge_recursive, utimately producing the config you want with your own custom-built generators. You're at liberty to configure whole sets of config with one method, so you can create a resource configurator which sets up the controller invokables, the routes, and anything else required in one method.
array_merge_recursive FTW!
Enjoy! :)
"Some commonly used features, such as user management, comment management, may be developed in terms of modules so that they can be reused easily in future projects." - http://www.yiiframework.com/doc/guide/1.1/en/basics.module
I have a lot of projects that requires a user. Every time quite the same database structure and features. Registration, login, logout etc.
Yii tells me that i can reuse modules. Cool... let's start:
I have 3 parts: User, Campaign and Website.
In this project the CampaignModule has a relation to the UserModule (campaign_user [user_id, campaign_id])
The WebsiteModule has a relation to the CampaignModule and to the UserModule.
I want to reuse the UserModule in other projects with features like registration, login, edit etc.
Actual situation:
After creating models with gii every one has relations and dependencies across the modules.
e.g.
UserModule: 'campaigns' => array(self::HAS_MANY, 'Campaign', 'user_id'),
To use the WebsiteModule it's necessary to include the User- and CampaignModule.
Now i even have to include Website- and CampaignModule to use the UserModule!
I also want to update the UserModule across many projects and maybe build a framework with some basic modules.
What is the right way to plan an architecture like this?
There is a yii-user module, what they do, is they allow you to specify additional relations for the User model, on the module configuration:
/**
* #return array relational rules.
*/
public function relations()
{
$relations = Yii::app()->getModule('user')->relations;
if (!isset($relations['profile']))
$relations['profile'] = array(self::HAS_ONE, 'Profile', 'user_id');
return $relations;
}
So you can do something like:
'modules'=>array(
'user' => array(
...
'relations' => array(
'categories' => array(CActiveRecord::HAS_MANY, 'Category', "user_id"),
'account' => array(CActiveRecord::HAS_ONE, 'Account', "user_id"),
),
...
),
),
I am trying to figure out how do you generate models for modules in ZF? My logic could be flawed, but here is the setup:
I have a ZF Structure setup for modules. I have a Blog Module and a Game Module. I wish for both of these systems to be independent of each other, but share the same common modules, such as user accounts, they would be hosted under separate databases IE a Blog Database and a Game Database and a Core database. So my structure would look like:
ZF /
- applications /
- configs
- controllers
- models
User.php
- modules
- blog
- controllers
- models
Blog.php
- views
- games
- controllers
- models
Games.php
- views
- views
I am just a bit confused on how you can get doctrine to generate the models for individual modules. I could be looking at this completely wrong, if anyone can shed some insight I would totally appreciate it, short of manually doing it. Back to trying to do some more research for it see if I can find the solution.
Thanks.
AFAIK you can't generate them in your way :( , sorry for that .
i ran into same problem once before and i think the best solution is to generate the Models out of the application folder and put them into the Library folder so the structure would be
ZF /
- applications /
- configs
- controllers
- models
- modules
- blog
- controllers
- models
- views
- games
- controllers
- models
- views
- views
-library/
-your_custom_namespace
-Model
User.php
Blog.php
Games.php
so all of your model would have the same prefix + save the time and pain of manually editing each generated model to fit to its namespace .
down below my doctrine cli
<?php
echo "Hello Tawfek ! , Howdy ?? \n";
/**
* Doctrine CLI
*/
error_reporting(E_ALL);
define('ROOT_PATH', realpath(dirname(__FILE__)));
define('APPLICATION_PATH', realpath(dirname(__FILE__) . "/../"));
define('APPLICATION_ENV', 'development');
//Ensure library/ is on include_path
set_include_path(implode(PATH_SEPARATOR, array(
'../library',get_include_path(), "/home/Sites/site/library/" )));
/** Zend_Application */
require_once 'Zend/Application.php';
// Create application, bootstrap, and run
$application = new Zend_Application(
APPLICATION_ENV,
APPLICATION_PATH . '/configs/application.ini'
);
// Read in the application.ini bootstrap for Doctrine
$application->getBootstrap()->bootstrap('doctrine');
// Create the configuration array
$config = $application->getOption('doctrine');
// (Note you can have all of these in application.ini aswell)
$config['generate_models_options'] = array(
// Define the PHPDoc Block in the generated classes
'phpDocPackage' =>'site',
'phpDocSubpackage' =>'Models',
'phpDocName' =>'Your Name Goes here',
'phpDocEmail' =>'Your Email',
'phpDocVersion' =>'1.0',
// Define whats what and named how, where.
'suffix' => '.php',
'pearStyle' => true,
'baseClassPrefix' => 'Base_',
// Unless you have created a custom class or want Default_Model_Base_Abstract
'baseClassName' => 'Doctrine_Record',
// Leave this empty as specifying 'Base' will create Base/Base
'baseClassesDirectory' => NULL,
// Should make it Zend Framework friendly AFAIK
'classPrefix' => 'Dagho_Model_',
'classPrefixFiles' => false,
'generateBaseClasses' => true,
'generateTableClasses' => false,
'packagesPath' => APPLICATION_PATH "/../library/Dagho/Model" ,
'packagesFolderName' => 'packages',
);
$cli = new Doctrine_Cli($config);
$cli->run($_SERVER['argv']);
?>