Archive for the ‘Zend Framework’ Category

Plugins in Zend Framework

Thursday, September 1st, 2011

There is no way you haven’t noticed that the Zend Framework documentation is pure garbage, almost every example they have is useless, there is no context, lacks of more in depth case of use and the quickstart makes you wonder if you really need to use something so complex to create something so simple.

I visit the crappy documentation for a quick reference, then I search for a more detailed explanation on google and 90% of the time there will be a link to a page that clearly explains the functionality I’m searching for and even goes deeper into some subjects.

Ok, enough of my complaints, let’s get to business.

One project I worked recently used the following approach for reusable constructor methods.

It creates a base controller with most common methods and all other controllers inherit from that base controller.

This looks like a good idea. Pretty simple and functional but then I came across this page.

As you can read it encourages others to use the helpers and plugins instead of a base controller. Even though at first it sounds like the base controller approach is justifiable you’ll later realize that helpers or plugins are a better option.

In my case there is a part of the app reserved for logged users so I needed to check the permissions to see if the controller should show something or ask a user to log in.

I read Matthew’s post and decided to go along with this approach. The whole explanation is right there, nevertheless it’s missing a little bit of info regarding the plugins/helpers folder location and how to make them available for your application.

I wanted my app folder schema to be consistent so I decided I’ll have my helpers and plugins folders under the application one.

Next thing to do is make them available; I did this in the bootstrap by adding the following method:

<?php
    protected function _initAutoloader(){
        $moduleLoader = new Zend_Application_Module_Autoloader(array('namespace' => '', 'basePath' => APPLICATION_PATH));
        $moduleLoader->addResourceType('Plugin', 'plugins', 'Plugin');
        $moduleLoader->addResourceType('Helper', 'helpers', 'Helper');
        return $moduleLoader;
    }
?>

Ok, so now both paths are available so every plugin or helper class will be found under those directories.

The following step is to create a plugin and a helper.

My plugin is quite simple: if a session namespace exists it would mean my user is registered and then I would like to set a couple of view variables like the user’s email.

Please note the event I used. This took me to figure out why.

The file is called: registered.php under plugins folder as formerly stated.

<?php
class Plugin_Registered extends Zend_Controller_Plugin_Abstract{
    public static $doNotValidate = false;
    public function postDispatch(Zend_Controller_Request_Abstract $request){
        if(!self::$doNotValidate){
            if(!Zend_Session::namespaceIsset('credentials')){
                //Oops! user isn't logged in, get them somewhere else!
                $redirector = Zend_Controller_Action_HelperBroker::getStaticHelper('redirector');
                $redirector->gotoUrl('/');
            }
            else{
                //Nice! Proceed but set some variables first
                $namespace = new Zend_Session_Namespace('Credentials');
                //Get the view
                $viewRenderer = Zend_Controller_Action_HelperBroker::getStaticHelper('viewRenderer');
                if (null === $viewRenderer->view) {
                    $viewRenderer->initView();
                }
                $view = $viewRenderer->view;
                $view->email = $namespace->email;
                //Use the following line when view resource is given in application.ini (resources.view[]...)
                //Zend_Controller_Front::getInstance()->getParam('bootstrap')->getResource('view')->email = $namespace->email;
            }
        }
    }
}
?>

You’ll need to register the plugin and this is really easy.
Again get to the bootstrap. I typed the following code as pointed out by Matthew (it’s within the bootstrap).

<?php
    protected function _initPlugins(){
        $front = Zend_Controller_Front::getInstance();
        //Check if user is logged in
        $front->registerPlugin(new Plugin_Registered());
    }
?>

Now your plugin is registered.
Some static and public available pages won’t need to do this validation, so the controller body would look something like this:

<?php
class IndexController extends Zend_Controller_Action{
    public function preDispatch(){
        Plugin_Registered::$doNotValidate = true;
    }

    public function indexAction(){
        $this->view->headLink()->appendStylesheet($this->view->baseUrl('css/index.css'));
        $this->view->headScript()->appendFile($this->view->baseUrl('js/jquery.js'));
    }

    public function logoutAction(){
        Zend_Session::destroy();
        $this->_redirect('/');
    }
}
?>

The trick here is the preDispatch method. What happens is that it sets the flag before the plugin executes and so the plugin works as expected. If you need a controller to validate a user then you don’t have to set that flag.

Matthew’s post was enlightening. I’m starting to feel more comfortable with ZF now.

Helpers work pretty much the same. I’ll post it later.

Zend Framework – View – $this->url()

Thursday, August 11th, 2011

Been using ZF a lot. It hasn’t amazed me because even though it’s really powerful it’s still very complicated to achieve simple task and the official documentation is very very messy.

Anyway, I have this layout for a project with a main menu.

Each of the menu options link to a different controller, instead of hard coding the menu links I used ZF url helper so for every link I was using something like this:

$this->url(array('controller'=>'console','action'=>'index'));

Which when ran gave me the following link

/[project_folder]/public/console

This looked just fine. Later on I created a product’s catalogue and from there a link to see a product’s detail. The link was:

$this->url(array('controller'=>'catalogue','action'=>'details','pid'=>[product_id]));

Everything worked just fine so I clicked the products details link. Everything looked fine. Then I clicked one of the main menu links to get to another section of the web page and then a bug popped.

For some reason all the links where appended with the GET parameters so when I clicked on the info link it took me to

/[project_folder]/public/info/pid/[product_id]

And obviously I was getting an error because there was no ‘pid’ action for the ‘info’ controller.

I searched and read a couple of google results, give the documentation a try (it sucks) and after a while I ended up in a simple blog entry with the solution.

I only needed to change my code to this:

$this->url(array('controller'=>'console','action'=>'index'),null,true);

Now GET params are not appended to the URL’s and everything works fine 😀

PHP classes autoload (namespaces) in Zend Framework

Thursday, June 9th, 2011

On previous posts I created a function to dynamically load namespace classes.
Now that I’m using Zend Framework I was wondering how can I use the same namespaces in combination with Zend’s. Following the logic I only needed to register my autoload function so that everything starts working as I wish.
Having read through the documentation I was starting to think it would be very difficult but turned out to be quite simple so I’m posting my learning experience here hoping it would be useful for others.

Background

I have a bunch of namespaces being used for several applications. I have them stored in a specific folder. I use Mac OS.
Let’s suppose I have the namespaces folder located under /var so the namespaces folder path is: /var/namespaces/
Also I have a folder with several non namespaced classes on the following path: /var/classes/

I can’t change paths because several other non ZF applications use that, and I won’t be copying and pasting them into the ZF library path cause if code needs to change I have them all in just one single place.

My ZF application is stored in the following path: /Users/spiro79/web/sites/ZFapp/

ZF must work and be able to load the classes from the different namespaces.

Making it work

I will be using the same logic used in previous posts regarding the autload. Believe it or not is pretty simple.
All changes are done within the bootstrap so open it.
First of all we need to create the autoload function. I wrote this code as a Bootstrap public static function.

    /**
     * Autoload function for PHP namespaces
     * @param string $class
     */
    public static function getMoreNamespaces($class){
        $class = strtolower($class);
        if(strpos($class,'\\')!==false){
            $class = preg_replace('/\\\/',DIRECTORY_SEPARATOR,$class);
        }
        $possibilities = explode(PATH_SEPARATOR, get_include_path());
        $found = false;
        foreach($possibilities as $path){
            if(file_exists($path . DIRECTORY_SEPARATOR . $class . ".php")){
                $found = true;
                require_once $path . DIRECTORY_SEPARATOR . $class . ".php";
                break;
            }
        }
    }

What this code does is that it searches for the namespace folder within all paths set on the include path.
The autoloader will call this function to try to load the namespaces classes.
Now let’s set the namespaces and classes folders in the application.ini file, just add these lines and make them match your own path.

nmspcspth = "/var/namespaces"
clssspth = "/var/classes"

The third and last step is to add my autoload function to the default autoloader. I did this by typing the following code also within the Bootstrap.

    /**
     * Init the autoloader for PHP namespaces
     */
    protected function _initMoreNamespace(){
        $namespacesPath = $this->getOption('nmspcspth');
        $classesPath = $this->getOption('clssspth');
        define('PHP_CLASSES_PATH',$classesPath);
        define('PHP_NAMESPACES_PATH',$namespacesPath);
        set_include_path(get_include_path() . PATH_SEPARATOR . PHP_CLASSES_PATH . PATH_SEPARATOR . PHP_NAMESPACES_PATH);
        $autoloader = Zend_Loader_Autoloader::getInstance();
        $autoloader->unshiftAutoloader(array('Bootstrap','getMoreNamespaces'));
    }

Done! Now you can use natural namespace syntax like:

Use Utils\Config as MyConfig;
$configObj = new MyConfig;
$otherNs = new Utils\Tool();

My problem has been solved and now I can proceed with development 😀

Multiple databases support on ZF

Wednesday, June 8th, 2011

Zend Framework is nice but learning it is very confusing and time demanding. Official doc isn’t that clear, lacks of good examples and sometimes is outdated. Whenever I want something to be done I read the official documentation and then google it so I can get a good picture of what everyone did.

One thing that I recently needed was to enable multiple schema support for a specific project. One schema stores client info, the other stores products. One very interesting thing is that the products schema depends on the account so clients for region 1 should use a schema called reg1, while clients from region 2 a schema called reg2.

So the products schema kind of switches dynamically according to users setup.

The first thing to do is setup the config file. This is the easy part, I added some lines that looked like this:

resources.multidb.maindb.adapter = oracle
resources.multidb.maindb.persistent = true
resources.multidb.maindb.host =
resources.multidb.maindb.username = usr
resources.multidb.maindb.password = usr123
resources.multidb.maindb.dbname = "(DESCRIPTION= (ADDRESS= (PROTOCOL=TCP)(HOST=oracle.host.com)(PORT=1521)) (ADDRESS= (PROTOCOL=TCP)(HOST=oracle2.host.com)(PORT=1521)) (LOAD_BALANCE=yes) (CONNECT_DATA=(SERVER=DEDICATED)(SERVICE_NAME=srvcnm)))"

resources.multidb.seconddb.adapter = oracle
resources.multidb.seconddb.persistent = true
resources.multidb.seconddb.host =
resources.multidb.seconddb.username = usr2
resources.multidb.seconddb.password = usr2123
resources.multidb.seconddb.dbname = "(DESCRIPTION= (ADDRESS= (PROTOCOL=TCP)(HOST=soracle.host.com)(PORT=1521)) (ADDRESS= (PROTOCOL=TCP)(HOST=soracle2.host.com)(PORT=1521)) (LOAD_BALANCE=yes) (CONNECT_DATA=(SERVER=DEDICATED)(SERVICE_NAME=srvcnm2)))"

resources.multidb.thirddb.adapter = oracle
resources.multidb.thirddb.persistent = true
resources.multidb.thirddb.host =
resources.multidb.thirddb.username = usr3
resources.multidb.thirddb.password = usr3123
resources.multidb.thirddb.dbname = "(DESCRIPTION= (ADDRESS= (PROTOCOL=TCP)(HOST=toracle.host.com)(PORT=1521)) (ADDRESS= (PROTOCOL=TCP)(HOST=toracle2.host.com)(PORT=1521)) (LOAD_BALANCE=yes) (CONNECT_DATA=(SERVER=DEDICATED)(SERVICE_NAME=srvcnm3)))"

Notice I’m storing everything in a multidb array with three different elements: maindb, seconddb and thirddb. Let’s consider the maindb to be the users schema, for products I’ll be switching between seconddb and thirddb.

First of all the main connection needs to be set so we can login, update, delete and o more stuff with a user account. Alo this connection will be set as the default adapter. I did this in the bootstrap. Here is the code:

/**
* Init the main database connection.
*/
protected function _initDatabase(){
    $applicationConfig = new Zend_Config_Ini(APPLICATION_PATH . '/configs/application.ini', APPLICATION_ENV);
    $config = $applicationConfig->toArray();
    $dbIni = $config['resources']['multidb']['maindb'];
    $db = Zend_Db::factory($dbIni['adapter'], $dbIni);
    Model_DbTable_Db::setDefaultAdapter($db);
}

So now we have the main connection up and working as a default adapter. This works the same as a basic database configuration. Now to the interesting part… set up the other database connection according to the user region. In my case the user’s account has a field/property that stores the correct products schema name so one of the things I’ll be doing is reading that property to know which schema I need to connect to for the products details. I won’t explain the account part because it’s quite simple.

We use a baseController from which we inherit all other controllers so we can easily concentrate most of the common methods in one single place. Within that baseController I added the following method:

/**
* Depending on the account we set up the adapter for the products tables
* @param Account A valid account object
*/
private function setProductsSchema(Account $account){
    if(!Zend_Registry::isRegistered('erpdb')){
        $applicationConfig = new Zend_Config_Ini(APPLICATION_PATH . '/configs/application.ini', APPLICATION_ENV);
        $config = $applicationConfig->toArray();
        $dbIni = $config['resources']['multidb'][strtolower($account->getSchemaName())]; // In this case $account->getSchemaName() may return 'seconddb' or 'thirddb' 😀
        $erpdb = Zend_Db::factory($dbIni['adapter'], $dbIni);
        Zend_Registry::set('erpdb',$erpdb);
    }
}

Now the application is able to dynamically choose the proper schema for products according to the account. It’s important to add it to the registry with a name, in this case is erpdb. This is necessary in order to let the DbTable objects know which schema they’ll use. Be sure to call this method before making a query to the secondary schema.

Now let’s set up the DbTable objects so they know which connection they’ll be using. Right now all DbTable objects are using the default adapter set in the bootstrap, for those objects that refer to products we need to make them aware that they’ll be using the secondary connection. doing this is pretty straightforward.

Go to your DbTable object and add the following method:

/**
* Set the default adapter for this object
*/
public function init(){
    $this->_setAdapter('erpdb');
}

That’s it! Notice that we set the adapter name the same as the db registry added before.

And that’s basically all we need to do to make the connection dynamic 😀

Hope it helps.

Forms and encoding

Sunday, May 8th, 2011

Ok, Zend Framework has lots of components to do almost anything.
One of the coolest is the form component, it reduces the time spent coding a form and it’s validation and you can then reuse the form code wherever you want and it will behave exactly the same.
One thing was annoying me. When in a form element label you use accents the label, once parsed, will display either weird characters or the raw html code.
For example take a look at this code:

$this->addElement('text','email',array(
            'size'=>'50',
            'label'=>'Correo Electr&oacute;nico*',
            'required'=>true,
            'validators'=>array('NotEmpty','EmailAddress')
            ));

I wanted it to read: Correo Electrónico, but instead of ‘ó´it was displaying a weird character or the raw html code for an accented ‘o’ (&oacute;) so I was wondering how can I solve this. It didn’t take me a lot of time to figure this one out, the solution was simple and elegant. When declaring a form element there is a flag that will handle if the label gets escaped or not.

The only thing I did was to change the element declaration from the former to this:

$this->addElement('text','email',array(
            'size'=>'50',
            'label'=>'Correo Electr&oacute;nico*',
            'required'=>true,
            'validators'=>array('NotEmpty','EmailAddress'),
            'escape'=>false
            ));

That’s it, it works.
Oh, BTW, I have my encodings set to ‘utf-8’, if you have ‘iso-8859-1’ you may leave your accents without encoding as html.

Zend Framework 101

Tuesday, February 8th, 2011

Ok, it’s being a while since I last published something here.

I’ve been digging into Zend Framework trying to understand everything so I can code easily. So far I’ve discovered that way too many PHP programmers get confused about three basic definitions.

Zend Framework

As stated before, Zend Framework is a library with a bunch of classes for almost everything (Auth, ACL, DB connections, etc.) this is important, cause I’ve noticed that way too many PHP programmers are confused with ZF being a new way of coding and setting up your application.

With pure Zend Framework you may use any class you want whenever you want to use it, just be sure to include the ZF library path and you’re done.

MVC

Now, while reading about ZF programmers may found a lot of talk about MVC, this stands for Model-View-Controller which is a coding paradigm I won’t explain cause there’s a lot of info about it in the web (Google it).

Here is where you start dealing with the bootstrap, configuration file, error handling and main setups.

ZF Tool

This stands for Zend Framework tool which basically is a bat/bash script that you may use from the command line to automatize some coding if you’re using Zend Framework and MVC. It’s pretty useful and you have the possibility to modify/enhance this script as you wish. If you won’t be coding with MVC you might as well forget about this tool.

Having these three basic definitions we can start discussing the framework. ZF, as I already stated, has a bunch of useful classes which are very simple to use. I know some of you will raise your voice and argue that it isn’t and that you have to place code in the bootstrap and then make a later call in a model and it might become confusing, if so let me remind you that right now I’m just writing about the ZF not being used within a MVC coding paradigm. By this I’m trying to make you understand that ZF can be used to code applications as you being doing for years as long as you are used to OOP.

Let’s see an example of how ZF helps you code faster. I’ll do a simple auth script.

I wont be pasting any HTML or javascript code, I’m assuming you can figure those out.

So, suppose you have a form that sends the login and password to dologin.php, in the php file you’ll have something like this:

<?php
/***********
Include's, require's, session's code.
**********/
/* After receiving, validating and filtering your input you'll define where do the user credentials are stored */
$login = $_REQUEST['login'];
$password = $_REQUEST['pass'];
//Create a database adapter
$dbAdapter = Zend_Db_Table_Abstract::getDefaultAdapter();
//Create the auth adapter
$authAdapter = new Zend_Auth_Adapter_DbTable($dbAdapter);
//Configure the auth adapter with the proper table name and credential fields.
$authAdapter->setTablename('users')
->setIdentityColumn('login')
->setCredentialColumn('password');
//Give the auth object the info to validate
$authAdapter->setIdentity($login)
->setCredential($password);
//Call the auth instance
$auth = Zend_Auth::getInstance();
//Validate
$result = $auth->authenticate($authAdapter);
//Some code to process the response
if(!$result){
//Go to login, credentials are wrong
}
else{
//Store identity
//Get user data, but avoid retrieving the password
$userData = $authAdapter->getResultRowObject(null,'password');
//Write data to auth object so object is modified
$auth->getStorage()->write($userData);
}
//Do more stuff
?>

So that’s it for the login. It’s pretty simple, and you can make it even more complex by adding some constraints, for example a user row that indicates if that user has been deactivated (Play with it and read the ZF documentation regarding this).

Now let’s say you want a page only to be available for logged in users. You won’t need to authenticate again your user, just call the auth object like this:

<?php
//Some code of your own
//Get auth object
$auth = Zend_Auth::getInstance();
if($auth->hasIdentity()){
echo('You\'re in!');
}
else{
echo('Ooops! sorry, you need to login first');
}
?>

So there you go, quite simple isn’t it.

Hope this helps you start playing with ZF. I’ll post more stuff in the go.

Thoughts on Zend Framework

Thursday, October 21st, 2010

Well I’ve jumped into the Zend Framework development… finally!

At first glance it looks like a mess, create the environment, separate models, views and controllers, configure the app, the bootstrap…. When I started working here (my current job, which I can’t give the name due to the terms of my job contract) I was hired because of my knowledge of PHP. Business owners stated that they needed a high profile PHP programmer. They said they were moving towards PHP development under Zend Framwork. Cool! a new learning experience.

I must say that when I got here I wasn’t familiar with ZF so it was a whole new experience. Days went by, and anfter a couple of months I have realized what is Zend Framework and why everybody thinks it’s too complicated. There is a big confusion even from Zend.

The confusion begins from the ZF tutorial. They start explaining you about MVC… here’s the whole confusion.

Zend Framework is a set of libraries that can help you with RAD, it has nothing to do woth MVC paradigm.

MVC is a coding paradigm, such as the three layers paradigm. You can code your whole application in whatever paradigm you wish and still use Zend Framework, but Zend treats both the paradigm and the set of libraries as the same. I’m not arguing that something is wrong, what I’m saying is that Zend Framework is one thing and MVC coding paradigm is a whole different one.

Do not be confused! MVC & ZF are a great, neat way of doing things but, as every technology, you should evaluate if both are needed for every project. If you are coding a simple web service then you might not need to use MVC but still use the framework to RAD.

Do a little research, clarify your needs and make the perfect choice for the case you’re dealing. Sometimes MVC can create a lot of garbage folders and files that wont be used at the end of the day.

Remember: KISS (Keep It Simple, Stupid)