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']);
?>
Related
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 have a quite big project that I need to program. I used to code with CodeIgniter but since they stopped maintaining the framework, I decided to switch to another. I chose Phalcon framework. The folder structure of the application that I want to implement is next:
app/
controllers/
admin/
users/
UsersController.php
UserGroupsController.php
dashboard/
system/
another_subfolder/
AnotherSubFolderController.php
production/
settings/
SettingsController.php
dashboard/
flow/
another_subfolder/
AnotherSubFolderController.php
website1/
customers/
CustomersController.php
CompaniesController.php
another_subfolder .... /
models/
sub_folder_structure/ // The same as controllers
This is just example of the folder structure of the application. There will be quite a lot of folders and sub-folders in this project to make it manageable.
From my understanding I need to register all namespaces at the loader for each sub-folder, so that Phalcon knows where to search and load the class.
//Register an autoloader
$loader = new \Phalcon\Loader();
$loader->registerNamespaces(array(
// Main
'Controllers' =>'app/controllers/',
'Models' =>'app/models/',
// Admin Routing
'Controllers\Admin'=>'app/controllers/admin',
'Models\Admin'=>'app/models/admin',
'Controllers\Admin'=>'app/controllers/admin',
'Models\Admin'=>'app/models/admin',
'Controllers\Admin\Users'=>'app/controllers/admin/users',
'Models\Admin\Users'=>'app/models/admin/users'
))->register();
The loader will look quite big.
Then I have to set-up the router so that requests redirected to the right controller. Right now I have next:
// Setup Router
$di->set('router', function(){
$router = new \Phalcon\Mvc\Router(false);
$router->removeExtraSlashes(true);
$router->add('/', array(
'namespace' => 'Controllers',
'controller' => "login"
));
$router->add('/:controller/:action/', array(
'namespace' => 'Controllers',
'controller' => 1,
'action' =>2
));
$router->add('/admin/:controller/:action/', array(
'namespace' => 'Controllers\Admin',
'controller' => 1,
'action' =>2
));
$router->add('/admin/users/:controller/:action/', array(
'namespace' => 'Controllers\Admin\Users',
'controller' => 1,
'action' =>2
));
return $router;
});
That will be also very big if I need to manually setup router for each sub-folder and namespace.
So the questions that I have are this:
Is there any way to make a loader prettier and smaller? As it will grow bigger.
How can I setup router so that I don't need to enter all of the namespaces and combinations of subfolders? Is there any way to make it smaller? May be modify dispatcher or any other class? Or is there a way I can set a path variable in the router to the location of the controller?
I have researched Phalcon documentation but could not find the way to do that.
Any help and suggestions are very much appreciated.
Thanks
Ad. 1. You can change your namespaces to be more PSR-0 (in my opinion), so I would make:
app
controllers
Admin
Users
UsersController.php
The you can register one namespace Admin or any other. Then you need to register only the top most namespace to work (keep in mind that your UsersController must have namespace Admin\Users\UsersController; to work). Thena autoloader should have only:
$loader
->registerDirs(
array(
// It's taken from my config so path may be different
__DIR__ . '/../../app/controllers/'
// other namespaces here (like for models)
)
);
I'm using registerDirs so I only point loader to the folder in which some namespace exists.
Ad. 2.
For this you can use groups of routes so you can pass a namespace as a parameter for config array of constructor and then do the repeative task in one place. Then just create new instances with different parameters;
$router->addGroup(new MahGroup(array('namespace' => 'Mah\\Controller'));
So inside MahGroup class could be:
class MahGroup extends Phalcon\Mvc\Router\Group {
public function _construct($config = array()) {
$this->setPrefix('/' . $config['perfix']);
$router->add('/:controller/:action/', array(
'namespace' => $config['namespace'],
'controller' => 1,
'action' => 2
));
// etc...
}
}
And then configuring routes:
$router->addGroup( new MahGroup(array('prefix' => 'mah-namespace', 'namespace' => 'Mah\\Namespace' )) );
$router->addGroup( new MahGroup(array('prefix' => 'mah-other-namespace', 'namespace' => 'Mah\\Other\\Namespace' )) );
But given examples for second question are just what could be done. I usually create Group class for each namespace and then declare some routes that my app uses since I'm not using english names for routes and I need rewriting polish urls to controllers which have also some namespaces.
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
Normally, for a Silex project, I would have top-level directories like:
- app/
- views/
- src/
- vendor/
- web/
Now, some of my classes may call $app['twig']->render(...) and it will pull out a view from the app/views folder.
If I extract a library to be more reusable, across multiple projects, where should I keep its view files, and how do I instruct Twig to look there?
The same question applies to graphics/stylesheets, etc which I would normally put in web/.
Surely they have to be within vendor/my-lib somewhere to allow Composer to cleanly install the files? Is there a common/best-practice way to do this?
Update
For reference, here's what I ended up doing:
<?php
// in my \Silex\ServiceProviderInterface ...
/**
* #var \Twig_Environment $twig
*/
$twig = $app['twig'];
// Add the paths to our twig templates here
$fsLoader = new \Twig_Loader_Filesystem(array(
__DIR__.'/views/'
));
$twig->setLoader(new \Twig_Loader_Chain(array($twig->getLoader(), $fsLoader)));
Thanks.
I store the views under src/{Library}/{Class}/View/
I set the base path of Twig to the src
$app->register(new TwigServiceProvider(), array(
'twig.path' => array(
__DIR__ . '/../src/{Library}/'
),
'twig.options' => array('cache' => false, 'strict_variables' => true)
));
and when calling render I pass in the path from that point
$app['twig']->render('{Class}/View/{twigfile}.html.twig',$data);
I have following structure in my Zend-Project :
-application
- PDF
- configs
- controllers
- models
- views
- Bootstrap.php
-library
-public
-tests
I have created a new folder PDF inside application folder. And I have write some classes inside it[PDF].
What I want is to access this classes inside the indexAction() of the IndexController, but it showing an error like :
"Class 'Application_PDF_FormDocument' not found in D:\xampp\htdocs\zendapp\application\controllers\IndexController.php on line 13"
What may be the possible reason?
Please provide some help.....
Thanks In Advance......
I agree with ChanibaL regarding the naming of your classes. you should be naming it PDF_FormDocumnet.
Next, in application.ini, regerster the namespace:
autoloaderNamespaces[] = "PDF_"
Lastly, in your index.php make sure you are adding it to the include path:
set_include_path(implode(PATH_SEPARATOR, array(
realpath(APPLICATION_PATH . '/../library'),
realpath(APPLICATION_PATH),
get_include_path(),
)));
That should do the trick
If you have a standard autoloader in your application, the class name should be PDF_FormDocument (no Application_ part!) in the file application/PDF/FormDocument.php
If this doesn't help by itself try adding
protected function _initAutoload() {
$autoloader=new Zend_Application_Module_Autoloader(array(
'namespace' => 'PDF',
'basePath' => dirname(__FILE__).DIRECTORY_SEPARATOR.'PDF'
));
to application/Bootstrap.php