Amazium bvba, your online partner
Modular application with Zend Framework
  • Share post with Twitter
  • Share post with StumbleUpon
  • Share post with Delicious
  • Share post with Digg
  • Share post with Technorati
  • Share post with Blinklist
2009-06-16 18:08

Modular application with Zend Framework

zend_application, zend_tool, modules, zend framework

I admit. I am a sucker for modules. I like my code nicely seperated in manageable blocks, that I can reuse whenever I want. Needless to say, I'm a big fan of the modules in Zend Framework.

Download article as PDF | Download sourcecode

It isn't always very easy to set it up though. I had to look long and hard for answers on several questions and I noticed a lot of people had the same ones. So, I decided to make an article on creating a modular application in Zend Framework.

Pre-requisites

I'm assuming you have already downloaded Zend Framework and have configured your system, so we can use Zend_Tool and the zf scripts to set up our application. If you haven't, you can find a link to my blog at the bottom of this article. Zend_Tool isn't really necessary when setting up an application, but it makes it very easy and assures that your application follows the default directory structure.

Setting up the application

Create a directory that will hold your application, on Debian this is under the /var/www directory by default:

dev:~# mkdir /var/www/amazium
dev:~# cd /var/www/amazium
dev:~# zf create project .
Creating project at /var/www/amazium

This creates the project and the initial structure:

Let's see what files are important to us.

First of all you have the public directory. This will not only hold the index.php file that will start your application, but also public files such as images, css files, javascript files, etc...

Then you have the library directory. If you have your own library, this is where you can put it. I will briefly touch how you can add it to your application.

The test directory will hold the unit tests. This can be used to test your models which should contain the business logic, but also the actual pages themselves.

Last but not least there is the application directory. This can be considered as the most important one. I must confess that in the past, I tried to put as many things like helpers, filters, models in my own library. But I've seen the light! It's actually far simpler to use the directory structure as defined by Zend Framework.

Digging into the application directory

configs

Inside the configs directory, you will find a file called application.ini. This file will be used to define your basic application configuration. We will see later how you can add your own resources to use this and to be auto loaded by your application. We will get back to this file on a number of occasions. Familiarize yourself with it, it will become one of your allies.

controllers

Inside the controller directory, you will find files for every controller. This is Zend Framework 101, so I'm not going into detail. When you get to modules, don't forget to prepend your module name to the class name (i.e. Admin_IndexController).

models

Inside the models directory, you can put your models. There is a lot of discussion to what a model is and here's my take: a model contains your business logic, but is not tied to a storage engine. This basically means that for me a model does not extend the Zend_Db_Table class. Under models you can put a directory DbTable and then put your data classes in there. It adds a level of abstraction and probably for a lot of people also an extra level of difficulty, but it's just good practice basically.

views

The views directory holds the view scripts, but also view related things such as filters and helpers. In the default directory layout the filters and layouts are not added, but we will do that manually later.

Adding your private library

My library is called Amz (short for Amazium) and contains some library classes I wrote in the past. Let's say I want to add this, I just add following entry in the config.ini:

autoloaderNamespaces.amz = "Amz_"
autoloaderNamespaces.other = "AnotherLibrary_"

2 things to notice: since our application expects autoloaderNamespaces to be an array, you need add a key. This means you can add multiple custom libraries by writing multiple lines as above. The second thing to notice is to add an underscore at the end of your library prefix. If I would have only specified AnotherLibrary, this would actually have opened the door for classes such as AnotherLibraryThatIDontWant_Aclass).

Adding your first module

Ok, so that's it? Not really... you might have noticed we don't have a modules directory yet. Our application is still module unaware. So let's change that and add our first module, called "admin".

dev:~# zf create module admin
Creating the following module and artifacts:
/var/www/amazium/application/modules/admin/controllers
/var/www/amazium/application/modules/admin/models
/var/www/amazium/application/modules/admin/views
/var/www/amazium/application/modules/admin/views/scripts
/var/www/amazium/application/modules/admin/views/helpers
/var/www/amazium/application/modules/admin/views/filters
Updating project profile '/var/www/amazium/.zfproject.xml'

As you can see, it creates a new directory called "modules" in the application path. There it added the module directory "admin" with a similar structure for the module as we described above.

Let's create a new controller for the module so we have something to show. Now, in the current version of Zend Framework, this WILL return an error. The listing below is what you SHOULD get. There are patches in the ZF bugtracker, but they don't solve the full problem. The best thing to do for now, is to manually create the controller and actions for modules. See the comments for more info.

dev:~# zf create controller index index-action-included=1 admin
Creating a controller at /var/www/amazium/application/modules/admin/controllers/IndexController.php
Creating an index action method in controller index
Creating a view script for the index action method at /var/www/amazium/application/modules/admin/views/scripts/index/index.phtml
Creating a controller test file at /var/www/amazium/tests/application/ modules/admin/controllers/IndexControllerTest.php
Updating project profile '/var/www/amazium/.zfproject.xml'

If you ran the patches and got code generated, verify that 1/ the correct files were generated (index/index.phtml under admin/views/scripts), 2/ that the indexAction was added to the new IndexController (and not the default one) and 3/ that your controller's class name was prefixed by your module name. It didn't work as expected for me and I ended up creating the files manually.

Now, if you try it in the browser, you get an error "Message: Invalid controller specified (admin)".

So, what did we do wrong? Nothing actually. You would expect your application is now module ready but it isn't. You created a first module, true... but you needed some extra configuration. So, let's open the application.ini we discussed earlier and add following lines to the end of the production block:

resources.frontController.moduleDirectory = APPLICATION_PATH "/modules"

resources.modules[] = 

Reload the page in the browser and you should get something...

Now, since we want to harness the full power of modules, we'll add a bootstrap first. The bootstrap will enable the use of class resources, but also make all models, filters, helpers, etc... available to your whole application.

Create the file Bootstrap.php under your admin directory and add this code:

class Admin_Bootstrap extends Zend_Application_Module_Bootstrap
{
}

Also modify the Bootstrap.php in your application path by adding this function:

protected function _initAppAutoload()
{
    $autoloader = new Zend_Application_Module_Autoloader(array(
        'namespace' => 'App',
        'basePath' => dirname(__FILE__),
    ));
    return $autoloader;
}

This will autoload to models, filters, helpers, etc... for our default module.

With both setup, we'll be able to access all these from our controllers later on.

Adding some layout

I bet you weren't really amazed by how it all looked? Well, that's because we didn't have a layout specified yet. Okay, the default index had some, but the layout should not be defined there. I will show you how to add your own layouts (which won't look spectacular either though :D).

Let us create a few directories first:

dev:~# cd /var/www/amazium 
dev:~# mkdir public/images
dev:~# mkdir public/css
dev:~# mkdir public/js
dev:~# mkdir application/views/layouts

Now, create a file default.phtml and admin.phtml in the layouts directory and add your layout code to it. This is a very simple template, chich just shows the content but is good to explain how to add the layouts. Replace the h1 title by the module name so you see a different template is loaded.


<?php echo $this->doctype() ?>
<html>

<head>
    <?php echo $this->headTitle() ?>
    <?php echo $this->headMeta() ?>
    <?php echo $this->headLink() ?>
    <?php echo $this->headStyle() ?>
    <?php echo $this->headScript() ?>
    <base href="/" />
</head>

<body id="page-home">
    <h1>Default</h1>
    <?php echo $this->layout()->content ?>
</body>

</html>

To get the layout working, you add the layout path and default layout to the application.ini file. Notice how we added a module resource entry for the layout as well. This will do nothing actually.... yet.

resources.layout.layoutPath = APPLICATION_PATH "/views/layouts"
resources.layout.layout = default
admin.resources.layout.layout = admin

When you switch between your default en admin module, you'll see that it uses the same layout. One might think that prepending the second line with "default." will enable layouts specific to the module, but unfortunately it doesn't. It will use the last specified template, in our case the admin, as default. To mitigate this, we will use a controller plugin since we need access to the request object to decide which template to show.

I created Amz/Controller/Action/Helper/LayoutLoader.php and added following content:

class Amz_Controller_Action_Helper_LayoutLoader
extends Zend_Controller_Action_Helper_Abstract
{

    public function preDispatch()
    {
        $bootstrap = $this->getActionController()
                         ->getInvokeArg('bootstrap');
        $config = $bootstrap->getOptions();
        $module = $this->getRequest()->getModuleName();
        if (isset($config[$module]['resources']['layout']['layout'])) {
            $layoutScript =
                 $config[$module]['resources']['layout']['layout'];
            $this->getActionController()
                 ->getHelper('layout')
                 ->setLayout($layoutScript);
        }
    }
    
}

Then I added a loader for it in the bootstrap:

protected function _initLayoutHelper()
{
    $this->bootstrap('frontController');
    $layout = Zend_Controller_Action_HelperBroker::addHelper(
        new Amz_Controller_Action_Helper_LayoutLoader());
}

If you reload your admin / default page, you should now see the module specific layout.

Spicing up the application with a model

For me a model is about business logic. It shouldn't about where you get data, but about what you do with it. Unfortunately there currently isn't a "Zend_Model" class you can abstract and use. So everyone basically invents his own system, or just plainly extend the DbTable. I've seen a very interesting implementation by Matthew Weier O'Phinney on the Dutch PHP Conference. The models had a data mapper which could be referenced for the data, while the model itself did what it was there for. Unfortunately it is out of the scope of this article to go very deep on it, so I'll make a very simple model that doesn't do a lot at all: A color model. Basically it generates a hex color that can be used in html.

Create the file Color.php in your application/models directory:

class App_Model_Color
{
    
    public function getRandomHtmlColor()
    {
        $red = rand(0,255);
        $green = rand(0,255);
        $blue = rand(0,255);
        return $this->getHtmlColor($red, $green, $blue);
    }

    public function getHtmlColor($red, $green, $blue)
    {
        $color = '#' . $this->_getHex($red)
                     . $this->_getHex($green)
                     . $this->_getHex($blue);
        return $color;
    }
    
    protected function _getHex($number, $digits = 2)
    {
        return substr(str_repeat('0', $digits) .
                         dechex($number), - $digits);
    }
    
}

As you can see it allows you to get a random color or to convert 3 integers to an html color. As I said.... nothing spectacular.

Modify the indexAction of your IndexController :

public function indexAction
{
    $model = new App_Model_Color();
    $this->view->color = $model->getRandomHtmlColor();
}

Lastly modify your view script (views/scripts/index/index.phtml) :

My random number is : <?php echo $this->color; ?>

When you refresh your default page, it should now show another html color each time you refresh. Now, that was easy wasn't it? But how come it recognized the model without any trouble? Well, the _initAutoload function that we specified for the bootstrap takes care of it. Since we specified App as the "prefix", our default modules will be available as App_Model_*. If you had created a DbTable directory, they would be available as App_Model_DbTable_*.

In the same way you can put models in the modules. You don't have to specify an autoloader there. The module bootstraps take care of everything for you. Instead of the App, the module name will be the prefix. In our example models would be available as Admin_Model_* and Admin_Model_DbTable_*.

Custom View Helpers

I tried the same with view helpers and you can get them autoloaded the same way. But there is a catch... apprantly the view looks for Zend_View_Helper_* instead of the expected App_View_Helper_*. Since I wanted to use the App variant, I solved this by adding following line in the config.ini :

resources.view.helperPath.App_View_Helper = APPLICATION_PATH "/views/helpers"

Now, let's create a view helper that displays a text in a certain color.

Create a file views/helpers/ColoredText.php and add following code:

class App_View_Helper_ColoredText extends Zend_View_Helper_Abstract
{
    
    public function coloredText($text, $color)
    {
        $text = $this->view->escape($text);
        $ctext = '<span style="color: ' . $color . '">' .
                     $text . '</span>';
        return $ctext;
    }
    
}

Change the view script by following code:

My random number is :
<?php echo $this->coloredText($this->color, $this->color); ?>

When you refresh the page now, you should see the color name displayed in the actual color it represents.

Conclusion

So, we have created a new modular application. We have tied in a library, we have tied in module specific layouts, we have worked with models and view helpers. There are a zillion other things you can do, but most of them are covered in the many tutorials online that don't specifically cover modules.

I hope this was useful for you, feel free to send in your comments.

See you in the PHP universe!

Jeroen Keppens

Links

My Blog

http://blog.amazium.be

Article as PDF

Download article as PDF

Sources

Download sources for the article

Article about setting up Zend Tool

http://blog.amazium.be/blog/setting-up-new-zend-framework

Comments and Feedback

andrea c 21

00-1-11-30 00:00
I try to follow this tutorial but if I type localhost/admin I have an application error If I echo the module I read "default" so what i did wrong ? thank you
# zf create controller index index-action-included=1 admin
this command answers error : "This project already has a controller named index"

It seams that the module name isn't used and zf tries to create the controller in the default module.
It looks like I forgot to copy a footnote (you can see it in the PDF) :

"In all honesty I ran into a few problems the first time I tried because of bugs in Zend_Tool. I saw some patches in the bugtracker, so I assume they will be included in one of the upcoming minor releases (if they haven't been already): verify that 1/ the correct files were generated (index/index.phtml under admin/views/scripts), 2/ that the indexAction was added to the new IndexController (and not the default one) and 3/ that your controller's class name was prefixed by your module name."

I think one of the upcoming minor releases will have the actual fix for that bug. In the meantime I patched my Zend library as specified here:

http://framework.zend.com/issues/browse/ZF-6853

But that didn't do the trick 100% either since it tried to add the index action to the default index file (hence all the verifies in the footnote which I will add to the article in a couple of minutes).

My opinion is that until the fix is there, you go trough the manual labour of creating the controllers and actions. It's a little bit more work, but at it gets the job done.
Good tutorial. I have a few doubts about modular application with Zend Toold standard structure and this post clarify some of them. I would like to add some comments and questions:

1.- Why layouts inside /applications/views/layouts, and not inside each module views folder: admin layout inside /application/modules/views/layouts? This breaks "independancy" of a module...

2.- Models. I used to include all the models of my app in a one and single "models" at the application level, indeed using modules concept (I also love it). I believe this was the only way of using models along all my app - modules, but as you explain is not. I can use models from any module in other modules, can't I?

Finally you gave a few answers but generate a question also: A big part of my models are Zend_Db_Table_Row extensions. They are responsibles of saving, reading data, among of doing bussines logic with data of cours. But you suggest this is not right. Why? Where the DB layer should be according to you?. I know this is not the topic of the post, but it is an interesting topic I would like to get other points of view.

Thanks.
Good tutorial. I have a few doubts about modular application with Zend Toold standard structure and this post clarify some of them. I would like to add some comments and questions:

1.- Why layouts inside /applications/views/layouts, and not inside each module views folder: admin layout inside /application/modules/views/layouts? This breaks "independancy" of a module...

2.- Models. I used to include all the models of my app in a one and single "models" at the application level, indeed using modules concept (I also love it). I believe this was the only way of using models along all my app - modules, but as you explain is not. I can use models from any module in other modules, can't I?

Finally you gave a few answers but generate a question also: A big part of my models are Zend_Db_Table_Row extensions. They are responsibles of saving, reading data, among of doing bussines logic with data of cours. But you suggest this is not right. Why? Where the DB layer should be according to you?. I know this is not the topic of the post, but it is an interesting topic I would like to get other points of view.

Thanks.
One more question:

Using Zend_Tool let us starting an application in a quick way. All data of the application are written to a hidden .xml file. But what happen when, after started, we start to create controllers, actions, views in a "manual" way? the data in .xml it is not "synced" with the real structure from that moment, so, is it possible to still using Zend_Tool once an app has been manually growed?
Hi,

You make a good point abou the module independancy. What I would propose is that you optionally alay define the layoutpath for the module. In the action helper you could then check if it was set and add it to the layout paths.

In my real life application I go a bit further. I have a module.ini in a configs dir which holds the module config instead of defining modulename.* in application.ini.

About the modules: Yes you can. But be carefull of your module independance then. I'd say put the common classes in the default models directory. Reference other modules from the default module if you have to, but avoid tying the seperate modules' models in other modules if you want independance.

About Zend_Tool... I think with the current state of the code where you need to do manual actions, you make a valid point. I myself use it for setting up my initial app after which I add all extras I want. When I need a new module, I'm usually copying one of the other modules structure so it includes the bootstrap, config, etc... I might write a blog post about extendinf ZT so it has that functionality as well...

Greg Wessels

2009-06-18 16:53
Great article and good timing. I just put out an to-do list application (same day as your post) built with Zend Framework using a modular design as well. Its called Dodo and you can download the full source code for the app. dodo.threadaffinity.com

joedevon

2009-06-18 19:10
I love the text of your tutorials Jeroen, but did want to give you some constructive feedback. My eyes are terrible after so many years on computers and reading white text on a dark screen, especially code, makes me more likely to skim an article than read it. Otherwise I get eyestrain. Thanks.
I'm actually already looking for a good new template because I think the width of the articles is bad. I'll keep the color comment in mind, you make a good point.

joedevon

2009-06-18 19:20
Thanks!
There you go... 250 pixels wider and a lot brighter ;)

Atir Javid

2009-06-18 22:25
Hello. Thank you very much for a great tutorial.

I have also posted a tutorial on this a while back, a bit different than yours. I basically shed light on how to do exactly what you are doing, but only to start the app.

http://www.atirjavid.com/Zend-Framework-Tutorials/Zend_Application/index.html

Zend_Tool just doesn't work yet, so I'm not even bothering with it. I'll go the manual route and create everything like we all have been in the past.

One thing I don't understand fully is why you are adding an _initAutoLoad() method to your bootstrap. Simply to add the module specific models as well global models can be done via the front controller plugin through your routeShutDown or preDispatch. What do you think?

Also I noticed that Zend_Tool doesn't support a "Conventional Modular Directory Structure" as described in the reference guide. I am a sucker for that particular organization method so that is the one that I chose.

Thank you again for an excellent article.

peterwang

2009-06-19 18:13
Thanks for you great post, a small question please: in function _initLayoutHelper(), is
"new Amz_Controller_Action_Helper_Layout" should be "new Amz_Controller_Action_Helper_LayoutLoader" ?
Thank you Peter. You are correct. I had initially called it layout, but decided to call it LayoutLoader afterwards.

I've modified the article.
As others have pointed out, there are some issues regarding modules as standalone applications that can be easily redistributed. The layouts issue is easily solved, but major issues arise in regard to public assets (e.g. css/js/etc) and library dependencies. I propose that for reusable modules, we place all dependent public assets under the module directory itself, and then use symlinks or rewrite rules so they can be accessed on the web. For library dependencies, I think we should look into creating an application resource that can resolve any dependency issues when the module bootstrap is called.
Chris 2009-06-20 16:43

resources.modules[]

This line seems to give an error with me... what does it do ?
That initializes the module application resource. Try resources.modules = ""

SkinBlogger

2009-06-22 16:56
Yeah I'm experiencing an interesting issue (makes sense, but not desirable):

With the admin bootstrap, I created an initViewHelpers function and set the stylesheet to admin.css (worked fine).

Well, I then went to the default bootstrap and created an initViewHelpers function that set the stylesheet to default.css. Also worked fine for the default site, however, after going to the admin area I noticed that both default.css and admin.css were added to the page.
Well, it's important to note that all bootstraps are loaded and executed. So if you want module specific code, you have to execute this in a controller plugin or action controller helper.

It's not a bug, but intended behaviour actually.
Andrea, could you provide a bit more info please. It's hard to say what went wrong based on your text. The error might be a good start.
I have similar issue .. I have db resources defined for each module in main application.ini .... but for some reason, it is always using parameters for module listed last in the resources list, when I am accessing any module specific actions .. e.g. /module1/action or /module2/action ...
Hello Jeroen. First of all, sorry for my English. I love your serie of tutorials about programming Zend Framework modules :) Thanks a lot!

When implementing your code, I thought it may be better placing libraries under the module directory (/modules/modulename/library). Ok, there will be duplicated files, but this way they are definitely a standalone selfcontained pieces, ready to copy and paste into any ZF app.

What do you think?

Thank you again for your work :)
Hi Friend,! Congratulations for this nice looking blog. In this post everything about Web Development. I am also interested in latest news, Great idea you know about company background. Increasing your web traffic and page views Add, add your website in www.directory.itsolusenz.com

Seraphees

2009-06-26 09:26
I downloaded the code, and ran the program, but there has a error like this?

Fatal error: Uncaught exception 'Zend_Application_Bootstrap_Exception'
with message 'Resource matching "frontcontroller" not found' in
C:\wamp\www\Amazium\library\Zend\Application\Bootstrap\BootstrapAbstract.php:605
Stack trace:
#0 C:\wamp\www\Amazium\library\Zend\Application\Bootstrap\BootstrapAbstract.php(540):
Zend_Application_Bootstrap_BootstrapAbstract->_executeResource('FrontController')
#1 C:\wamp\www\Amazium\library\Zend\Application\Bootstrap\BootstrapAbstract.php(497):
Zend_Application_Bootstrap_BootstrapAbstract->_bootstrap('FrontController')
#2 C:\wamp\www\Amazium\library\Zend\Application\Resource\Layout.php(48):
Zend_Application_Bootstrap_BootstrapAbstract->bootstrap('FrontController')
#3 C:\wamp\www\Amazium\library\Zend\Application\Bootstrap\BootstrapAbstract.php(594):
Zend_Application_Resource_Layout->init()
#4 C:\wamp\www\Amazium\library\Zend\Application\Bootstrap\BootstrapAbstract.php(537):
Zend_Application_Bootstrap_BootstrapAbstract->_executeResource('layout')
#5 C:\wamp\www\Amazium\library\Zend\Applicat ...
in C:\wamp\www\Amazium\library\Zend\Application\Bootstrap\BootstrapAbstract.php on line 605
How to fix it?
Thanks for this wonderful tutorial. It helped me better understand modules in ZF. I only have one question: how can I use images, css and js for a module. I know that I can put these files into the www directory but I would prefer my module to be in a single folder rather than a few folders which I copy to different places in order for the module to work.
excellent! thank you

andrea c

2009-06-28 13:52
Thank you Jeroen, I fixed my last problem now I need to load differents css and js for every module like SkinBlogger said but I didn't understand how to do it. Thank you again.
Hi, thanks for your tutorial,

I have a problem because when I go to localhost/admin I get a error and when I do a die($module) on LayoutLoader.php its always show "default",do you can help me
i have book marked this site on delicious forums list
Nice tuturial, but my application dies with no errors, just blank skreen, when I tried to use modules botstrap. I have to redefine __construct method in module's bootstrap class and avoid of use parent's constructor.

I tried to debug, but can't find why that happens.
@chuso I can see some use-cases where you might have specific library code that your module needs. However, most can be put in models, helpers, etc... which ZF already supports.

If you really want to add library paths under your modules, you will need to configure this in your general application.ini or overwrite the module bootstrap to include this.
@Seraphees I noticed you're on windows. I haven't tested it there and I don't use it in daily life, so I'm afraid I won't be able to help you out on that one. Maybe someone else who uses windows can help Seraphees out?
@andre @andrea_s Good question! I think you will need to put them separately in your public folders, but it kind of defeats the self-containing module principle.

If you find a good solution, feel free to share it here.
@Comma I hate when PHP does that... did you see anything in your apache's error log? sometimes the errors go there...

Juan Pablo Stange

2009-07-04 14:37
Theres a bug concerning Zend Tool, just for all the people who has short tags off.

http://juanpablostange.blogspot.com/2009/07/zf-tool.html

andrea c

2009-07-07 11:44
@jeroen
I do in this way but I don't think is the better way.
In module bootstrap I remove default application headScript and headTitle in the _initView function, and then I re-append new css or new script or new headTitle.
How do I manage this structure in a shared server. According to you the document root will be the public directory. But in shared server the root directory of ftp is htdocs, so how do I manage here?
Great !!!
Thank you !

andrea c

2009-07-16 15:44
@Jeroen my solution doesn't work because bootstrap inside admin modules is always loaded, in default module as well
I am new to zend framework... and in a big problemetic situation right now....

I am making a website that has some categories displayed on main page..When user clicks on a category he goes into category page with list of articles in it...

And when user clicks on article he goes to article content page....

So my urls go like this

http://localhost/public/categoryname
http://localhost/public/categoryname/articlename
For a new article in that category...
http://localhost/public/categoryname/articlename/new
In my application.ini i am using

resources.router.routes.username.type = "Zend_Controller_Router_Route"
resources.router.routes.username.route = ":categoryname/:articlename/*"
resources.router.routes.username.defaults.controller = "category"
resources.router.routes.username.defaults.action = "index"
resources.router.routes.username.reqs.username = "[a-z0-9-]+"
it doesnt work....

if i use this.

resources.router.routes.username.type = "Zend_Controller_Router_Route"
resources.router.routes.username.route = ":categoryname/*"
resources.router.routes.username.defaults.controller = "category"
resources.router.routes.username.defaults.action = "index"
resources.router.routes.username.reqs.username = "[a-z0-9-]+"
it does not go beyond category controller page....

So here do i have to make one controller that is categorycontroller and multiple actions under it or multiple controllers or do i need to
mention multiple routes which dint work when i tried...

Please help ....

Regards
Kusum
www.datashuffler.org : zend data mapper
@Babi I think this is a general Zend Framework question actually.

You can have a look at following blog post by Lorenzo Alberton: http://www.alberton.info/zend_framework_mod_rewrite_shared_hosting.html.

I have just done a test and you can very simply put your index.php file (which normally resides in your public dir) in the root dir. You will have to edit following line though:

defined('APPLICATION_PATH')
|| define('APPLICATION_PATH', realpath(dirname(__FILE__) . '/../application'));
TO

defined('APPLICATION_PATH')
|| define('APPLICATION_PATH', realpath(dirname(__FILE__) . '/application'));
You can keep the rest of your files (css, js, images, etc...) in public if you want, but then you need to put /public/js/blahblah.js in your layout files and views.

Hope this helps.
@kusum I'm no expert on routing. Have you tried the ZF MVC mailing list?

http://framework.zend.com/wiki/display/ZFDEV/Mailing+Lists

To subscribe just send a mail to fw-mvc-subscribe@lists.zend.com. Once you're subscribed you can ask the question there.

Maurício Vinicius de O. Santos

2009-07-22 13:50
Nice post man...
It's also good to know how Zend tool works.
There is a thing that I'm little confused.

You said that the business logic are into models...
The business logic are not at Controllers? And in the Models aren't there the ORM classes?
I'm following your blog since now...And I have a blog about Zend Frame work too (in Portuguese)
Bye and thank you.
@ Santos, models are business logic, models can contain data access logic too but then it becomes active record or db table instead of a true model. imagine this, you have a customer class, your boss wants you to make a csv_customer_loader that can take a paramter of a csv file containing hte data and return a fully formed customer object. If your model is coupled to the database code this type of stuff is not possible. Your code should not be coupled to the database schema at all! ( unless you know the implications and have fully analyzed that that would be ok for that project, usually this is for simpler apps, for complicated apps check out www.datashuffler.org ). It is a datamapper implementation that helps you uncouple your object model and DAO ( data access objects )
@santos Same as Josh said :)

I played a bit with code I got from Matthew Weier O'Phinney during the Dutch PHP Conference which had following parts:

Model <-> Datamapper <-> DbTables

It worked quite well (although not being stable as it was work in progress), but in the project I was doing on it was overkill.

I haven't had a look at Josh' DataShuffler yet, but it's on my to do list for august (the download has been shining on my desktop for 2 weeks now, but didn't get to it yet). I'm pretty sure if Josh nailed the querying part, I will be an avid supporter and user of his classes because we need something in ZF to handle the model part.

Maurício Vinicius de O. Santos

2009-07-22 20:48
hum...
It will be good if I'd have a project to see it running on Zend...
it might be a simple project that uses this "way" to create the models.

Does any body could help me with any example?
I've read the url you gave me (http://www.datashuffler.org/#setupmodels)
but I'd like to see it running with ZF.

thank you very much about your explanations.
Querying with Shuffler is as simple as overloading the select() method to do your own querying, the load() method only depends on an associative array of fields. They can come from a query ( simple or complex ) csv file or whatever implementation you provide.

Later on you will be able to set any individual mapping as aggressive or lazy and it will build the queries. I had prototypes working but I still have to write / refine more of the tests and refactor but I release that.
Great tutorial. Everything works fine.

BUT... :)

I extended your tutorial with unit tests and got an error.

Fatal error: Call to a member function getOptions() on a non-object in
D:wwwBigBosslibraryBigBossControllerActionHelperLayoutLoader.php on line 11
it seems that "$bootstrap = $this->getActionController()->getInvokeArg('bootstrap');" doesnt work in testing.

do you know why?

p.s.: sorry for my english. I m not a nativ speaker.
Great tutorial however one question that I have is what do I need to do or change to use the admin template for errors within the admin module. For example if you go to something.com/admin/fubar it now displays the default template and I would like the admin template to be used.

Thanks in advance
Chris within the error controller you can set the layout.

I use an action helper:

$layout = Zend_Layout::getMvcInstance();

$layout->setLayout( $layoutName );

karlofthedead

2009-08-03 10:24
At last a good starting tutorial for modular application with the new Zend_Application :)! I've been looking for this for days.

Thanks a lot ^^.
I have not used modules because I haven't found a good example of how to manage the Auth and ACL issues.

I want a single User Login module to manage the logistics of authenticating users and determining their roles. I want the login's modules authentication to determine which pages are accessible in the main application and other modules.

Any suggestions or examples?
@steve

A Front Controller plugin that checks the session and changes the dispatch paramaters if the user is not authenticated, you could read the controller & action being dispatched and check the ACL for a corresponding resource, there is some example code out there I found

http://zendguru.wordpress.com/2008/11/05/zend-framework-acl-with-example/

Hey first thx for that nice tut it helped us a lot. But we are facing the same issue Niko posted above that we cant run the unit test properly.

Fatal error: Call to a member function getOptions()
on a non-object in ...LayoutLoader.php on line 11
$bootstrap = $this->getActionController()->getInvokeArg('bootstrap');
returns null ! when we run a Zend test case. Is there any explanation why this happened ?? Looking forward for your answer

Thomas

Hari K T

2009-08-19 08:41
@chris
resources.modules[] =
@andrea

Downloading and working on the code , is not showing any errors.
But when we add a Bootstrap.php in the modules/admin its having an infinite loop I think that makes the page not loading and getting the error .
I removed the Bootstrap.php of the modules/admin and its working fine after that .
Don't even know we need Bootstrap.php for the admin module .

Thanks Jeron for your wonderful tutorial .

Hari K T
If I want to use Zend_Form(with decorators) within admin module,where do I want to put the form directory and do I want to add resources for that to application.ini.

Troy Marker

2009-09-07 04:06
I created a project based on this tutorial. Every seems to be work except I have having a problem with layouts inside the module. My application renders that layout script fine for the main app, however, when it renders inside a module, it tries to render the layout script twice. This creates an error when trying to load a view helper.

I cannot find what is wrong. Could some please help me with this problem.

I want to use a layout in the main application to maintain a consistent look for the site. Any help would be greatly appreciated.

Thanks, Troy
Great tutorial.I use your libraries for my application.But now I have a problem about loading forms from actions.

If I store all forms in application/forms directory,are there any way to load that forms from actions in modules?

Thanks again.

Erick Rolando

2009-09-20 17:30
According to:

http://framework.zend.com/manual/en/zend.application.available-resources.html

application.ini should contain
resources.modules[] =

instead of just resources.modules[], it works for me.
Working fine on Windows after modification in application.ini.
Modified below as per Blah comment,

resources.modules[]=""
What it does. Any impact of above changes?
Nice tutorial!
Do you know there is a way for CustomerController to be extended by the rest of Controllers?

Thanks.
Great tutorial. Any chance you could post some code on how you load your module.ini configs?
Great tutorial Jeroen, thanks for doing this.

I'm fairly new to Zend Framework so this might be a stupid question, but can someone help me with setting up Zend_Controller_Router_Route_Module.

I find the documentation somewhat confusing.

Michiel Staessen

2010-01-07 15:30
What about a layout plugin?

class Plugin_Layoutloader extends Zend_Controller_Plugin_Abstract
{
public function
preDispatch(Zend_Controller_Request_Abstract $request)
{
$layout = Zend_Layout::getMvcInstance();
$layout->setLayout($request->getModuleName());
}
}

It's a lot shorter and easier to understand! :)
First of all: thanks for this tutorial! It's the best tutorial for dealing with Zend modules I've found so far.

Now to my question: I followed this tutorial and everything works so far. However, I do have problems when I want to use models inside the admin module. I created a model Color.php inside
application/modules/admin/models/ and tried to instantiate it in the index action of the Admin_IndexController with

$model = new Admin_Model_Color();
$this-view-color = $model-getRandomHtmlColor();

According to this tutorial this should work ("In the same way you can put models in the modules. You don't have to specify an autoloader there. The module bootstraps take care of everything for you. Instead of the App, the module name will be the prefix. In our example models would be available as Admin_Model_* and Admin_Model_DbTable_*."), however I get the following error message:

Fatal error: Class 'Admin_Model_Color' not found in
C:\xampp\htdocs\demo\application\modules\admin\controllers\IndexController.php on line 13.

Does anyone know what the problem is? I'm using Zend 1.10 and my application.ini looks like the following:

[production]
phpSettings.display_startup_errors = 0
phpSettings.display_errors = 0
includePaths.library = APPLICATION_PATH "/../library"
bootstrap.path = APPLICATION_PATH "/Bootstrap.php"
bootstrap.class = "Bootstrap"
resources.frontController.controllerDirectory = APPLICATION_PATH "/controllers"

autoloaderNamespaces.amz= "Amz_"

resources.frontController.moduleDirectory = APPLICATION_PATH "/modules"
resources.modules[] =

resources.layout.layoutPath = APPLICATION_PATH "/layouts/scripts"
resources.layout.layout = default
admin.resources.layout.layout = admin

[staging : production]

[testing : production]
phpSettings.display_startup_errors = 1
phpSettings.display_errors = 1

[development : production]
phpSettings.display_startup_errors = 1
phpSettings.display_errors = 1

I'm grateful for any hints!
First of all thank you for the kind words!

I will have a look the coming days to rewrite the tutorial to work with version 1.9 and 1.10. It was on my to do list after launching the new site & blog last weekend. :)

I'll keep you in touch!
Great, thanks for the support. I'm looking forward to the updated version!

By the way, could you also provide the source of your sample project? The link above (under section "Links") doesn't work anymore.
Hi all !

I had follow the tutorial, but I have one problem:)
When I want to load localhost/Project/public
It goes down and say:

Catchable fatal error: Argument 1 passed to Amz_Controller_Action_Helper_LayoutLoader::preDispatch() must be an instance of Zend_Controller_Request_Abstract, none given, called in E:\xampp\htdocs\SoftEng\library\Zend\Controller\Action\HelperBroker.php on line 265 and defined in E:\xampp\htdocs\SoftEng\application\modules\admin\LayoutLoader.php on line 5

The line 5 is: public function preDispatch(Zend_Controller_Request_Abstract $request){

Any IDEA? PLEASE HELP:)
Hi,

It was very easy for me to understand compared to others... thanks again... also i do have a doubt not regarding to this but to zend. Can i specify the path for application and library dynamically for another project through an existing zend project and if so how can i???:)
After searching a lot of tutorials, this was the only that worked! It is updated and works with ZF 1.10.

There was only one problem. This line:
resources.modules[]

should be:
resources.modules[]= ""

At least, that worked for me.
The tutorial is excellent. It would be even better if the author explains how to use Models from Admin Module.

As Ulrich says, models within the Admin module are not loaded.

"In the same way you can put models in the modules. You don't have to specify an autoloader there. The module bootstraps take care of everything for you. Instead of the App, the module name will be the prefix. In our example models would be available as Admin_Model_* and Admin_Model_DbTable_*."

This does not work, at least in version 1.10

Can you explain me why and how the Models from admin modules are autoloaded, if in the bootstrap you define this:

$autoloader = new Zend_Application_Module_Autoloader(array(
'namespace' = 'App',
'basePath' = dirname(__FILE__),
));

I don't understand how "App" namespace is related to admin module.

What part of the code is responsable of autoloading Models from specific modules ?

Thanks.
That was just what i was looking for!

Thanks!
Hi,

Great post, but i`m getting an erro when i paste the line resources.modules[] in my application.ini, they say application is missing an = in this line.

Please help me in this issue.

Thanks
I'd like to mention that module dirs are case sensitive in regards to the URL - at least on a Linux server. The reason should become obvious. This is not ideal since most people using the www expect case insensitive URLs.
Thank you so much. I've been struggling for days to get module specific layouts working.
@Jeroen,
thanks for article. You enlightened me how to use layout loader in different modules. My own realization was much worser. And thanks to Michiel, with plugins it is even better to do, but in that case i'm obliged to have one layout for each module.
Please forgive my ignorance, but I have two basic questions:
1. Where do I put the LayoutLoader.php file?
2. Where do I find the config.ini file? (for placement of autoloaderNamespaces.amz = "Amz_")

Thanks!
Jeroen,
I have been searching the web for a long time for something like this, I just worked through it, I had a little trouble with an old version of Zend Tool (solved that) and everything worked as per your tutorial.
Excellent work...this is an awesome tutorial!

Latishia

2010-07-10 11:38
Adding:

$this->_helper->layout->setLayout('admin');

to public function init() will set your layout source file. I placed the file in the default layout directory so I did not have to change the path setLayout use's to locate files. You can find the references at http://framework.zend.com/manual/en/zend.layout.quickstart.html .
Thanks, for the tutorial, I am facing a similar problem like Ulrich . I have created a admin module but not able to access the models from module.
I am getting a fatal error class not found
Fatal error: Class 'admin_Model_DbTable_Group' not found in C:\Program Files\Apache Software Foundation\Apache2.2\htdocs\care\application\modules\admin\controllers\GroupController.php on line 15

This is same for form in module.
Class 'admin_Form_GroupRegisterForm' not found in C:\Program Files\Apache Software Foundation\Apache2.2\htdocs\care\application\modules\admin\controllers\GroupController.php on line 14

Can you please help me, what need to loaded or what needs to be configured.
hey there :) thanks for the great tutorial

i'm not sure what version of zend framework you have used or if has anything to do with it...

it took me like 8h of continuous searching why the hell your code wouldn't work for my project considering the fact that even though i wasnt extending it, but rather following your code and adapting it to my existing code...

the problem was with this line in application.ini

resources.modules[] =

instead of it i have put

resources.modules = ''

and thus it ended my whole day long search :|

has it anything to do with, say zend framework version? or what the heck was actually happening :|

thanks again for you and your friends/commentors job :) and please, if you have any idea what was the problem in my case please tell me... i just want to know so that next time i will be an expert regarding this subject :) thank you
Finally a tuturial about modules that actually works... good work and thnx!

gladicosa

2010-12-12 05:55
Great explaining article, Thanks

It didn't change layouts until I added an else block after :
if (isset($config[$module]['resources']['layout']['layout'])) { ......} else {
$this-getActionController()
-getHelper('layout')
-setLayout('default');
}
Had anyone the same problem(and how it resolved?) or it just my mistake of some other parts?
Thanks for writting such a wonderful article.
I was unable to set module specific layout in zend 1.11. After some trial I found

there was only one problem. This line:
resources.modules[]

Finally I commented the line & it worked at least, that worked for me.
Thanks dude. This was a very helpful tutorial. Solved loads of puzzles for me.
I followed your tutorial and i appreciate the step-by-step guidelines in this tutorial. I regret for not seeing this page till now.

I expected to see an example of a module specific model... really cool stuff.
Looks like you are an expert in this field, good articles and keep up the good work, my buddy recommended me your blog.

My blog:
Credit Immobilier aussi credit Rachat De Credit
Just what i needed!!! thanks

seotools

2011-06-12 13:35
Amazing content!
Thank you for this share!
seo
Aaah...wonderful tutorial...
a bunch thanks from Mexico.
Zend is a really interesting tool, but IMO the reference is quite cryptic...
I also realize how useful can be the ZF tool.
you did great work, thank you

spotingbet

2011-06-24 15:57
www.amazium.com is awsome !!

rickylovexxzaq

2011-07-25 04:17
This website looks amazing and I am so happy to be a part of it. I just became a new member of the community.
_________________________________
Virginia Beach Roofing
This article helped me a lot .....

Thanks !!!

Add a Comment

Your email is never published or shared. Required fields are marked*