Share it

Bookmark and Share

Translate

Wednesday, August 22, 2012

0 First Zend application with module for Beginners

First Download the latest version of zend frame from Zend official website
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.
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'
Now, if you  try it in  the browser, you get an error "Message: Invalid controller 
specified (admin)".
1
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.
                                                       
1
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.Create the file Bootstrap.php under your admin directory and add this code:
<?php
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.
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:
<?php
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_Layout());
}
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:
<?php
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:
<?php
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.

0 comments:

Post a Comment

Thanks for your valuable Comment

 

TechnoTipworld- Tips,Tricks,Technology Copyright © 2011 - |- Template created by O Pregador - |- Powered by Blogger Templates