Zend Framework + Doctrine1.2 project structure with more modules - zend-framework

applications coupled with the realization ZendFramework + Doctrine 1.2 for some time, but now they have their first experience with the use of more modules. I requested a default module is visible to everyone with a certain layout and an admin module with a different layout.
So far in my applications I have always used the following structure:
/app
/application
/acls
/configs
/controllers
/forms
/layouts
/models --> models by doctrine
/generated --> base models by doctrine
/plugins
/views
/Bootstrap.php
/data
/doctrine
/data
/migrations
/schema
/schema.yml
/doctrine.php
/library
/public
/tests
So my question is: how should the structure of my application to do what is required?
I tried using zend tool and see what kind of structure I created the command:
zf create module admin
course after launching
zf create project app
I noticed that the create command module I created a folder modules in application.
Into modules created admin and inside it has created controllers, models and views.
So in addition to separating means zf controller and view correctly, but also models.
But my doctrine creates all the models on the one hand! :D
How can I do to use templates created by doctrine for each module?
Then how do I assign a new layout for the admin module?
For the party guest you advise me to leave the facility that currently use or move it all in a form default?
Sorry if I made a lot of questions, maybe too much, but I am really very confused about it!
Thanks

After a thorough documentation I've found the right project structure
/app
/application
/acls
/configs
application.ini
/layouts
/scripts
admin.phtml
default.phtml
/models --> models by doctrine
/generated --> base models by doctrine
/modules
/admin
/controllers
/forms
/view
/default
/controllers
/forms
/view
/plugins
/Bootstrap.php
/data
/doctrine
/data
/migrations
/schema
/schema.yml
/doctrine.php
/library
/public
/tests
To view a different layout according to where you are module I used the following plugins:
class Plugin_Layout extends Zend_Controller_Plugin_Abstract
{
/**
* Called before an action is dispatched by Zend_Controller_Dispatcher.
*
* #param Zend_Controller_Request_Abstract $request
* #return void
*/
public function preDispatch(Zend_Controller_Request_Abstract $request)
{
$layout = Zend_Layout::getMvcInstance();
$module = $request->getModuleName();
switch ($module) {
case 'default':
$layout->setLayout('default');
break;
case 'admin':
$layout->setLayout('admin');
break;
default:
$layout->setLayout('default');
break;
}
}
}
into Bootstrap.php file
/**
* #return Zend_Application_Module_Autoloader
*/
protected function _initAutoload()
{
$autoloader = new Zend_Application_Module_Autoloader(array('namespace' => '', 'basePath' => APPLICATION_PATH));
$autoloader->addResourceType('plugin', 'plugins', 'Plugin');
return $autoloader;
}
into application.ini file
resources.frontController.plugins.auth = Plugin_Layout
resources.layout.layoutPath = APPLICATION_PATH "/layouts/scripts/"
the plugin described above according to the module in use will set the layout with the name of module.phtml within "layouts/scripts".
How to Autoload forms within a module
add the two below lines to your application.ini file
resources.frontController.moduleDirectory = APPLICATION_PATH "/modules"
resources.modules[] = ""
Create a boostrap file for each module. The file, named Bootstrap.php, should be placed in the root of the module directory and the class name should be {module name}_Boostrap. This bootstrap file will cause zend framework to automatically add the new forms directory to the autoloader.
class Admin_Bootstrap extends Zend_Application_Module_Bootstrap {}
Add for form class to the /forms directory. A login form would have a filename of Login.php and a class name of {module name}_Form_Login
class Admin_Form_Login extends Zend_Form
Call your form from a controller file from within the same module
$form = new Admin_Form_Login();
Simple and effective! ;)

Related

Zendframework(1.12.11) view helper not found in phpunit

I have following directory structure for view helper in my zendframework project
--application
--views
--helpers
--Test.php
and configuration setting in application.ini is
resources.view.helperPath = APPLICATION_PATH "/views/helpers"
and configuration in Bootstrap.php is
$view->setHelperPath(APPLICATION_PATH . "/views/helpers/");
in Test.php file naming convention is
class Zend_View_Helper_Test extends Zend_View_Helper_Abstract {}
and I am using helper function in module wherever I need it.When I run project via browser, application working fine without any error, but when I invoke phpunit for same application via command line I am getting error something like
Fatal error: Uncaught exception 'ErrorException' with message 'include_once(Zend\View\Helper\Test.php): failed to open stream: No such file or directory' in D:\
zend\ZendServer\share\ZendFramework-1.12.11\library\Zend\Loader.php:134
that means it's going to find Test.php file in zend server library view folder.I am not getting why it's working via browser and not working in phpunit via command line.
I got solution. I have replace my configuration setting of application.ini
resources.view.helperPath = APPLICATION_PATH "/views/helpers"
with
resources.view.helperPath.Application_View_Helper = APPLICATION_PATH "/views/helpers/"
and changed naming convention of Test.php with
class Application_View_Helper_Test extends Zend_View_Helper_Abstract {}
now zend loder will try to find view helper in application directory rather than Zend

Calling Zend Framework Service Layer from crons, SOAP, command line tasks and Queues

I am trying to find the best way to implement Model using Zend Framework for an enterprise application. From different articles I am now convinced that a Service Layer is a very good idea. I see that one of the arguments in favor of Service Layer is that - it can be called from outside - like from crons, SOAP, command line tasks and Queues.
But I am not clear how it can do so. When services are called from outside the Bootstrap will not run hence the model will have no information about the DB, Mail Transport, Logging etc.
Any suggestions?
The simplest way is to create a CLI script which is used to do your cron task.
You can bootstrap your application in the CLI script, just like it gets bootstrapped in the web end of things, using Zend_Application and the bootstrap class.
Just don't run the application, instead only bootstrap it. This way you will have access to the same environment as your web app has.
We're using a simple init.inc.php script that we include in our command line scripts and cronjob scripts, which bootstrap the resources that we need:
<?php
// Define path to application directory
defined('APPLICATION_PATH')
|| define('APPLICATION_PATH', realpath(dirname(__FILE__) . '/../application') );
// Ensure library/ is on include_path
set_include_path(implode(PATH_SEPARATOR, array(
realpath(APPLICATION_PATH . '/../library'),
get_include_path(),
)));
// we can't afford not have a APPLICATION_ENV, so return a fatal error in this case
defined('APPLICATION_ENV')
|| define('APPLICATION_ENV',
(getenv('APPLICATION_ENV') ? getenv('APPLICATION_ENV')
: ''));
chdir(APPLICATION_PATH);
/** Zend_Application */
require_once 'Zend/Application.php';
// Create application, bootstrap, and run
$application = new Zend_Application(
APPLICATION_ENV,
APPLICATION_PATH . '/configs/application.ini'
);
$resources = array('autoload', 'config', 'multidb', 'logger', 'cache', 'settings');
foreach ($resources as $resource) {
$application->bootstrap($resource);
}
set_time_limit(1200);
ini_set('memory_limit', '700M');
the $resources array is the bootstrap functions you wish to load
the APPLICATION_ENV is usually a variable set by .htaccess, so you'll have to set it a shell variable (or just include it in the init.inc.php)

Use default module's action helpers in another module with Zend Framework

I think I've tried everything I've found to solve this, including all the answers here on SO.
In my project there is an admin module, and then there's the default module. Now I want the admin module to use the default module's helpers. Preferably only if there isn't an admin module helper with the same name. Is this possible?
The error message I get is:
Message: Plugin by name 'HeadBase' was not found in the registry; used
paths: Admin_View_Helper_:
/application/modules/admin/views\helpers/
Zend_View_Helper_: Zend/View/Helper/
I use ZF 1.11
Found a solution. In the Bootstrap, add an init for helpers, like this:
protected function _initHelpers()
{
$this->bootstrap('view');
$view = $this->getResource('view');
$view->addHelperPath(APPLICATION_PATH . '/views/helpers/', 'Zend_View_Helper');
}
This adds the helper path APPLICATION_PATH . '/views/helpers/' for helpers whose class is prefixed with Zend_View_Helper.

Setup of Doctrine CLI not quite working

Still struggling to get doctrine working properly on my system. I have a yaml file that describes the structure of my database and tables. (I am following the tutorial on zendcast). I have my doctrine script file as
#!/usr/bin/env php
<?php
chdir(dirname(__FILE__));
include('doctrine.php');
and the doctrine.php file contains
<?php
// Define path to application directory
defined('APPLICATION_PATH')
|| define('APPLICATION_PATH', realpath(dirname(__FILE__) . '/..'));
// Define application environment
defined('APPLICATION_ENV')
|| define('APPLICATION_ENV', (getenv('APPLICATION_ENV') ? getenv('APPLICATION_ENV') : 'development'));
// Ensure library/ is on include_path
set_include_path(implode(PATH_SEPARATOR, array(
realpath(APPLICATION_PATH . '/../library'),
get_include_path(),
)));
/** Zend_Application */
require_once 'Zend/Application.php';
// Create application, bootstrap, and run
$application = new Zend_Application(
APPLICATION_ENV,
APPLICATION_PATH . '/configs/application.ini'
);
$application->getBootstrap()->bootstrap('doctrine');
$config = $application->getOption('doctrine');
$cli = new Doctrine_Cli($config);
$cli->run($_SERVER['argv']);
My application.ini excerpt is
autoloaderNamespaces[] = "Doctrine_"
;--
;Database
;--
doctrine.dsn = "mysql://root:softna#localhost/gepm2"
doctrine.data_fixtures_path = APPLICATION_PATH "/configs/data/fixtures"
doctrine.sql_path = APPLICATION_PATH "/configs/data/sql"
doctrine.migrations_path = APPLICATION_PATH "/configs/migrations"
doctrine.yaml_schema_path = APPLICATION_PATH "/configs/schema.yml"
doctrine.models_path = APPLICATION_PATH "/../library/Gepm/Model"
When I run:
D:\www\gepm2\application\scripts>php doctrine build-all-reload
I get the ff feedback:
D:\www\gepm2\application\scripts>php doctrine build-all-reload
build-all-reload - Are you sure you wish to drop your databases? (y/n) y
build-all-reload - Successfully dropped database for connection named 'doctrine'
build-all-reload - Successfully created database for connection named 'doctrine'
build-all-reload - Created tables successfully
build-all-reload - Data was successfully loaded
However when I check mysql only the database is created no tables are generated. I have struggled with this for a whole day. Someone help.
EDIT
All right I got it working now.But to be honest with you the only changes I made to the code was to
1. set the time zone,
2. remove the underscore from the end of the utoloaderNamespaces[] value so utoloaderNamespaces[] = "Doctrine_" became autoloaderNamespaces[] = "Doctrine" and
3. move the doctrine database declarations to the bottom of the [production] section in the applications.ini
I am so far behind on schedule with what I am working on that I cannot mess about with these changes to see which one or why it worked. I will do say later when I have some down time. In the meantime a more knowledgeable geek may be able to explain why it may have worked. cheers.
The way doctrine creates tables in the db is by loading the models and reading the definitions within each of these models. If the CLI is not able to load the models then the table creation will fail. Unfortunately the CLI task does not report this.
Further I would advise you to check other CLI tasks such as generate-migrations-diff and migrate. I have had issues with these in the past and have resolved them successfully.

Using forms with the Zend Framework

I'm relatively new to MVC and the Zend Framework. That being said, I feel like I have a hard time figuring out where Forms belong in my directory structure. I have a modular directory structure, so I don't know if there should be a single forms directory, or one within each module directory.
/application
/modules/
/default
/controllers
/views
/admin
/controllers
/views
Once you've decided a directory for forms, do you set that directory in the include path of the bootstrap? Or do you include the form in the controller that it's being used in?
How do you use forms with the Zend Framework?
It's a little late but in the current version of ZF this has been solved:
On the following page http://framework.zend.com/manual/en/zend.loader.autoloader-resource.html
The manual states:
30.3.2. The Module Resource Autoloader
Zend Framework ships with a concrete implementation of Zend_Loader_Autoloader_Resource that contains resource type mappings that cover the default recommended directory structure for Zend Framework MVC applications. This loader, Zend_Application_Module_Autoloader, comes with the following mappings:
api/ => Api
forms/ => Form
models/ => Model
DbTable/ => Model_DbTable
plugins/ => Plugin
As an example, if you have a module with the prefix of "Blog_", and attempted to instantiate the class "Blog_Form_Entry", it would look in the resource directory's "forms/" subdirectory for a file named "Entry.php".
When using module bootstraps with Zend_Application, an instance of Zend_Application_Module_Autoloader will be created by default for each discrete module, allowing you to autoload module resources.
This does, however, require the use of Zend_Application
add this in application/modules/yourmodule/Bootstrap.php file.
class Yourmodule_Bootstrap extends Zend_Application_Module_Bootstrap
{
protected function _initAutoload()
{
$autoloader = new Zend_Application_Module_Autoloader(array(
'namespace' => 'Yourmodule_',
'basePath' => APPLICATION_PATH .'/modules/yourmodule',
'resourceTypes' => array (
'form' => array(
'path' => 'forms',
'namespace' => 'Form',
),
'model' => array(
'path' => 'models',
'namespace' => 'Model',
),
)
));
return $autoloader;
}
}
As of March '09 the ZF thought leaders still seem to be debating the best ways to organize everything. There is a scaffolding-generator as a part of Zend_Tool slated for release in ZF v1.8. It's currently in the incubator, I tried it last week and it works, but there are not many components generated in its current state.
From the examples I've seen it seems that they are best managed separate from the models they interact with (this is from Zend Framework In Action):
/application
/modules/
/default
/controllers
/forms
ContactForm.php
LoginForm.php
RegisterForm.php
SupportForm.php
/models
Comment.php
User.php
Users.php
/views
/admin
/controllers
/views
However, I've also seen structured with the forms below the model directory. Matthew Weier O'Phinney shows how to use them for validation on models themselves:
/application
/modules/
/default
/controllers
/models
Comment.php
User.php
/Form
Comment.php
Login.php
Register.php
/views
/admin
/controllers
/views
To have your files automatically included be sure to name your classes using the underscore model.
For example, when Zend_Loader sees
class RegisterController extends Zend_Controller_Action
It looks in the php include_path for:
Zend/Controller/Action.php
Similarly, assuming the first structure above, if we include the 'default' module in our include_path:
# bootstrap.php
$rootDir = dirname(dirname(__FILE__));
define('ROOT_DIR', $rootDir);
set_include_path(get_include_path()
. PATH_SEPARATOR . ROOT_DIR . '/library/'
. PATH_SEPARATOR . ROOT_DIR . '/application/modules/default/'
);
include 'Zend/Loader.php';
Zend_Loader::registerAutoload();
You name your classes:
Forms_ContactForm
Models_User
Some programmers choose to put most of their files in the library so they don't have to add extra include paths:
/library
/My
/Form
Contact.php
Assuming the library folder is included, the class above would be named:
My_Form_Contact
Best of luck! -Matt
i personally like to keep them in my application folder, since i dont think they belong in the library and having just one folder makes autoloading them easier.
/application
/forms
/modules/
/default
/controllers
/views
/admin
/controllers
/views
/libray/
/Zend
and i just added the form path to the includes_path and i am good to go.
Personally, I found it easiest to put my module directory in the include path and name my form classes in the Zend Loader pattern.
Example directory structure (copying from Matt's answer):
/application
/modules/
/default
/controllers
/forms
Contact.php
Login.php
Register.php
Support.php
/models
Comment.php
User.php
Users.php
/views
/admin
/controllers
/views
Example form class names:
Default_Forms_Contact
Default_Forms_Login
Default_Forms_Register
Default_Forms_Support
I name my models and plugins similarly to keep things simple.
I hope this issue is addressed correctly in later versions of the Zend Framework.
UPDATE:
This structure doesn't work on *nix platforms. Found that out the hard way! The Zend Loader needs the module, forms, and models folders to be capitalized to work in a case sensitive environment.
the zend command tool can create forms for that:
zf create form product sales
where sales is the name of the module, the command tool create a directory form inside module sales and a file Product.php with a class:
class sales_Form_Product extends Zend_Form {
and you have to add a definition of de Zend_Application_Module_Autoloader, to define your module's directory
$selectexamname = new Admin_Form_examresults_Selectexamname();
$this->view->selectexamname = $selectexamname;
your class should have to define according to this format
class Admin_Form_examresults_Selectexamname extends Zend_Form {}
I put all my models in a folder in the library. Notion is my company's name.
/application
/modules/
/default
/controllers
/views
/admin
/controllers
/views
/libray/
/Zend
/Notion
/Form
This makes it easy to include and find files as you already have the library folder included.
Notion_Form_Login
Notion_Db_Manager_Login