Archive for the ‘Zend Framework’ Category

How to use/write resource plugins with Zend_Application

Sunday, May 2nd, 2010

(apply to ZF v1.10)

You have two types of resources:

- class resources (those methods that you define in your Bootstrap class and that starts with ‘_init’)
- plugin resources (those that you define externally and can trigger via application.ini file)

How do you automatically load an external resource from application.ini file?
This is pretty simple indeed. You only have to declare your resource in your config file as follow: “resource.<resource_name> = true”
note: we added ” = true” because otherwise our line would have been ignored since no value was defined to our <resource_name> variable. In next section, we will add some parameters therefore making explicit use of ” = true” useless.

How do you provide options to  your own external plugin resource?
Anything that will come after ‘resources.<resource_name>’ in your application.ini file will be considered an option and provided to your external resource upon instanciation.
If I write

resources.myplugin.option1 = 1
resources.myplugin.option2 = 2

Then ‘myplugin’ is automatically registered and will be instanciated with following options array ['option1' => 1, 'option2' => 2, 'bootstrap' => Object]
note: ‘bootstrap’ entry is automatically created by ZF (Zend_Application_Bootstrap_BootstrapAbstract) and therefore available to all plugins. It contains an instance of the bootstrap object.

Example:

in my application.ini, I have:

resources.db.adapter = “PDO_MYSQL”
resources.db.params.host = “localhost”
resources.db.params.username = “user”
resources.db.params.password = “pwd”
resources.db.params.dbname = “mydb”

Then what’s going to happen is:

  • Zend_Application_Resource_Db plugin will automatically get registered and bootstrapped
  • Options passed to Db plugin upon instanciation is an array:
    [
    'adapter' => 'PDO_MYSQL',
    'params' => [
      'host' => 'localhost',
      'username' => 'user',
      'password' => 'pwd',
      'dbname' => 'mydb'],
    'bootstrap' => Object
    ]

    note: for bootstrap entry, see above comment

How do you use Router resource?

ZF online documentation still contains example for old routing (ie. as it was performed prior to introduction of Zend_Application and external resources). Now it’s better to call external resource plugin rather than configure your Zend_Controller_Front as done previously.

To do this, it’s pretty simple. You can rely on examples provided in online documentation (http://framework.zend.com/manual/en/zend.controller.router.html), the only change that you have to do is to prefix all ‘routes’ entry in your application.ini file with ‘resources.router.’.

Thus,

routes.login.type = “Zend_Controller_Router_Route_Static”
routes.login.route = “login”
routes.login.defaults.controller = auth
routes.login.defaults.action = login

becomes

resources.router.routes.login.type = “Zend_Controller_Router_Route_Static”
resources.router.routes.login.route = “login”
resources.router.routes.login.defaults.controller = auth
resources.router.routes.login.defaults.action = login

That’s it. You don’t have to worry about anything else, a router instance is automatically created and your routes should be active now.

How do you use Log resource via .ini configuration?

In my case, I defined it this way:
resources.log.stream.writerName = “Stream”
resources.log.stream.writerParams.stream = APPLICATION_PATH “/../logs/app.log”
resources.log.stream.filterName = “Priority”
resources.log.stream.filterParams.priority = Zend_Log::WARN

Where can you access all instances used by external resource plugins?
Db plugin instanciates a Zend_Db_Adapter object, Log plugin instanciates a Zend_Log object, and so on…
Everytime a ->init() method of a resource plugin returns a value, this value is store in a container currently being a Zend_Registry instance (but not singleton).
As a consequence, once Db resource has been bootstrapped, you can access create db adapter instance in $bootstrap->getResource(‘db’); (and $boostrap->getResource(‘log’) for Log instance!)

How do you write your own external plugins?

  1. create your class extending Zend_Application_Resource_ResourceAbstract
  2. ensure your class implement ->init() method, which should perform all your bootstrapping and might return an instance to a shared object
  3. declare your plugin prefix and plugin path into application.ini:
    pluginPaths.My_Plugin_Prefix = APPLICATION_PATH "/path/to/my/resource/plugin/directory"
  4. call your plugin resource from application.ini:
    resources.myResource = true

    note: you can add parameters to this call (as explained above) that will be available in your resource plugin class via ->getOptions() method

Warning

  • execution order: by default, class resources get executed first
  • name overlapping: if your class resource has the same name as your external plugin resources, only your class resource will get executed
    example: in my Boostrap class, I have a method name ::_initDb() and in my application.ini file I initialize external Db resource (via ‘resources.db.xxx’ call), only my _initDb() will get executed. External plugin will simply be ignored
    => make sure you do NOT use the same name for your class resources and external plugin resources

sources

Zend Framework: remove call to favicon.ico via .htaccess file

Sunday, May 2nd, 2010

Almost all browser makes a query for /favicon.ico file.
When you use ZF, all your queries that do not match an existing physical file are rerouted to your bootstrap file and therefore go through your entire app to end-up in a 404 error.

Well this is a waste of computing resources and above all can drives you crazy when you’re tracking errors. You might not understand why your query runs twice on a single page load…

A quick and easy way to fix this is simply to create an empty file, name it ‘favicon.ico’ and place it in your /public folder.
If you want to skip the request call via .htaccess instead, simply preprend the following line to your rewrite condition:

RewriteEngine On
RewriteCond %{REQUEST_URI} ^/favicon.ico$ [OR]
RewriteCond %{REQUEST_FILENAME} -s [OR]
RewriteCond %{REQUEST_FILENAME} -l [OR]
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule ^.*$ - [NC,L]
RewriteRule ^.*$ index.php [NC,L]

That’s it.
Good luck.

sources

multiple sections in an .ini file

Sunday, May 2nd, 2010

When you define an .ini file, you can divide your content in sections so that you can load on some sections or you can even implement section inheritance so that you have customized values based on your given configuration.

Lets’ see a quick example:

$ini = <<<EOF
[base]
host=localhost
user=testuser
pass=testpass
database=default

[users:base]
database=users

[archive : base]
database=archive
EOF;

$opts = parse_ini_string($ini, true);
var_dump($opts);

//output
array(3) {
  ["base"]=>
  array(4) {
    ["host"]=>
    string(9) "localhost"
    ["user"]=>
    string(8) "testuser"
    ["pass"]=>
    string(8) "testpass"
    ["database"]=>
    string(7) "default"
  }
  ["users : base"]=>
  array(1) {
    ["database"]=>
    string(5) "users"
  }
  ["archive : base"]=>
  array(1) {
    ["database"]=>
    string(7) "archive"
  }
}

Inheritance mechanism is implemented in Zend Framework through Zend_Config_Ini class.

Splitting a section in multiple parts

Unfortunately splitting a section in multiple parts might not work as expected. Your entire section is overwritten and no simply merged.

Let’s have a quick look:

$ini = <<<EOF

[base]
host=localhost
user=testuser
pass=testpass
database=default

[users : base]
database=users

[archive : base]
database=archive

[base]
koko=kiki
EOF;

$opts = parse_ini_string($ini, true);
var_dump($opts);

//output
array(3) {
  ["base"]=>
  array(1) {
    ["koko"]=>
    string(4) "kiki"
  }
  ["users : base"]=>
  array(1) {
    ["database"]=>
    string(5) "users"
  }
  ["archive : base"]=>
  array(1) {
    ["database"]=>
    string(7) "archive"
  }
}

too bad…

sources

    ZF: Zend_Rest_Client::restDelete() ‘Unexpected error: No Method Specified’

    Thursday, March 4th, 2010

    When using Zend_Rest_Client & Zend_Rest_Server with ZF v1.10.2, to quickly build a Rest webservice, performing simple restDelete() queries ended up with following error message:

    Unexpected error: No Method Specified

    In fact, current implementation of Zend_Rest_Client::restDelete() does not provide any request parameter to queried url.
    On server side, Zend_Rest_Server expects the ‘method’ argument to be provided => above error is generated.

    To avoid this problem, I had to update Zend_Rest_Client with following updated method:

    /**
    * Performs an HTTP DELETE request to $path.
    *
    * @param string $path
    * @param array $query Array of GET parameters
    * @throws Zend_Http_Client_Exception
    * @return Zend_Http_Response
    */
    final public function restDelete($path, $query = null)
    {
    $this->_prepareRest($path);
    $client = self::getHttpClient();
    $client->setParameterGet($query);
    return $client->request('DELETE');
    }

    note: subclassing the class was not an option since most of its methods are ‘final’! Grrrr…

    For more information, look at corresponding tickets (see links below)

    sources

    Zend_Db: utf8 query string gets inserted as non-utf8

    Sunday, June 28th, 2009

    I had hell a hard time debugging this. I served an utf8 query string to insert some data, and when data were inserted (through Zend_Db_Adapter calls), it got inserted into db as non-utf8 strings!

    Worst part of this is that my db (and my table as well as the particular row in my table where I had this issue) were configured with utf8 as default charset AND uft8_general_ci as collation.

    Anyway, the solution I found (quick fix for now), is to explicitly tell the mysql connection resource that all queried string is on utf8 by prepending ‘SET CHARACTER SET utf8;‘ to my sql query.

    It would be better to find a way to automatically run this when sql resource is created so that all queries are properly treated as utf8, but so far it does the trick for me.
    If I find a better place where to put it, I will update this post.

    [UPDATE]
    I’ve found a better way where to specify which charset to use. It looks like since v 1.8.0, ZF natively handles this, simply provide a ‘charset’ option with appropriate value as done below:

    db.adapter = PDO_MYSQL
    db.params.host = localhost
    db.params.dbname = mydbname
    db.params.username = myusername
    db.params.password = mypwd
    db.params.charset = utf8

    (see http://framework.zend.com/issues/browse/ZF-1541)

    sources

    Zend_Pdf: align drawn text on right or center it horizontally

    Sunday, June 28th, 2009

    Below is the code I used to align drawn text on the right or center it within provided width.

    As stated in http://framework.zend.com/issues/browse/ZF-7144,  use of Zend_Pdf_Page subclass is not easy on ZF 1.8.4 => I subclassed Zend_Pdf and implemented within this class instead.

    Below code relies on function to find out width of text to be generated (see Zend_Pdf: find out width of text to be drawn) and also incorporates small code improvement to handle multi-line text (see Zend_Pdf: draw multi-line text).

    Here it is:

    <?php
    require_once 'Zend/Pdf.php';
    
    /**
    * Represent an order/bill pdf
    */
    class Library_Pdf_Base extends Zend_Pdf
    {
     /**
     * Align text at left of provided coordinates
     */
     const TEXT_ALIGN_LEFT = 'left';
    
     /**
     * Align text at right of provided coordinates
     */
     const TEXT_ALIGN_RIGHT = 'right';
    
     /**
     * Center-text horizontally within provided coordinates
     */
     const TEXT_ALIGN_CENTER = 'center';
     /**
     * Extension of basic draw-text function to allow it to vertically center text
     *
     * @param Zend_Pdf_Page $page
     * @param string $text
     * @param int $x1
     * @param int $y1
     * @param int $x2
     * @param int $position
     * @param string $encoding
     * @return self
     */
     public function drawText(Zend_Pdf_Page $page, $text, $x1, $y1, $x2 = null, $position = self::TEXT_ALIGN_LEFT, $encoding = null)
     {
      $bottom = $y1; // could do the same for vertical-centering
      switch ($position) {
       case self::TEXT_ALIGN_LEFT:
        $left = $x1;
        break;
       case self::TEXT_ALIGN_RIGHT:
        $text_width = $this->getTextWidth($text, $page->getFont(), $page->getFontSize());
        $left = $x1 - $text_width;
        break;
       case self::TEXT_ALIGN_CENTER:
        if (null === $x2) {
         throw new Exception("Cannot center text horizontally, x2 is not provided");
        }
        $text_width = $this->getTextWidth($text, $page->getFont(), $page->getFontSize());
        $box_width = $x2 - $x1;
        $left = $x1 + ($box_width - $text_width) / 2;
        break;
       default:
        throw new Exception("Invalid position value \"$position\"");
      }
    
      // display multi-line text
      foreach (explode(PHP_EOL, $text) as $i => $line) {
       $page->drawText($line, $left, $bottom - $i * $page->getFontSize(), $encoding);
      }
      return $this;
     }
    
     /**
     * Return length of generated string in points
     *
     * @param string $string
     * @param Zend_Pdf_Resource_Font $font
     * @param int $font_size
     * @return double
     */
     public function getTextWidth($text, Zend_Pdf_Resource_Font $font, $font_size)
     {
      $drawing_text = iconv('', 'UTF-16BE', $text);
      $characters    = array();
      for ($i = 0; $i < strlen($drawing_text); $i++) {
       $characters[] = (ord($drawing_text[$i++]) << 8) | ord ($drawing_text[$i]);
      }
      $glyphs        = $font->glyphNumbersForCharacters($characters);
      $widths        = $font->widthsForGlyphs($glyphs);
      $text_width   = (array_sum($widths) / $font->getUnitsPerEm()) * $font_size;
      return $text_width;
     }
    }

    So far it worked real great for him, I hope some folks will find it useful to and improve it.

    sources

    Zend_Pdf: draw multi-line text

    Sunday, June 28th, 2009

    As of ZF 1.8.4, if you try to draw a multi-line text through Zend_Pdf_Page::drawText() and it display all content within a single line.

    I quickly subclassed it with the following piece of code:

    // display multi-line text
    foreach (explode(PHP_EOL, $text) as $i => $line) {
     $page->drawText($line, $left, $bottom - $i * $page->getFontSize(), $encoding);
    }

    I hope it will be useful to some fellows out there.

    sources

    Zend_Pdf: find out width of text to be drawn

    Sunday, June 28th, 2009

    If you use Zend_Pdf to generate pdf content, you might be interested in finding the length of text to be drawn. Well at least I was, to be able to center text horizontaly within a box, to align it on the right and so on.

    I asked for help on zf mailing list and Gina-Marie Rollock kindly provided a solution she found on the internet, here it is:

    /**
    * Return length of generated string in points
    *
    * @param string $string
    * @param Zend_Pdf_Resource_Font $font
    * @param int $font_size
    * @return double
    */
    public function getTextWidth($text, Zend_Pdf_Resource_Font $font, $font_size)
    {
     $drawing_text = iconv('', 'UTF-16BE', $text);
     $characters    = array();
     for ($i = 0; $i < strlen($drawing_text); $i++) {
      $characters[] = (ord($drawing_text[$i++]) << 8) | ord ($drawing_text[$i]);
     }
     $glyphs        = $font->glyphNumbersForCharacters($characters);
     $widths        = $font->widthsForGlyphs($glyphs);
     $text_width   = (array_sum($widths) / $font->getUnitsPerEm()) * $font_size;
     return $text_width;
    }

    Code is not very explicit but in the end it works pretty well!
    I hope it will be useful to some fellows out there.

    sources

    ZF: clear registered errors on response object

    Wednesday, June 24th, 2009

    As of ZF v1.8.1, Zend_Controller_Response_Abstract has many ->clearXXX() methods, but not ->clearExceptions() methods.

    Well it’s a pity because sometimes you might need to clear raised exception!

    Let’s say you have a specific error type, that when raised, is catched by error-handler as any other exception, and then error-handler (or any other plugin) redirect to a normal action/controller query. Well on next postDispatch loop event, your response will still be flagged has having an error and will again be handled by your error controller => recursivity, here we come!

    Anyway, I’ve subclassed default Zend_Controller_Response_Http class to add such method:

    <?php
    /**
    * @package core
    * @subpackage global
    */
    
    require_once 'Zend/Controller/Response/Http.php';
    
    /**
    * Extend default Zend class to add clearExceptions() method
    */
    class Library_Response extends Zend_Controller_Response_Http
    {
     /**
     * Clear all registered exceptions
     *
     * @return self
     */
     public function clearExceptions()
     {
      $this->_exceptions = array();
    
      return $this;
     }
    }

    sources

    Zend_Form: checkbox is rendered with ’0′ as value [solved]

    Tuesday, May 12th, 2009

    If you want to render just the <input> node of a Zend_Form_Element_Checkbox (without label nor dt/dd wrappers…), you might be interested in calling $checkbox->renderViewHelper().

    Problem with this call is that you will end-up with a single <input> node (it’s corresponding hidden node does not get generated) and with a value of ’0′ when checked! => not good at all.

    Instead of directly calling $checkbox->renderViewHelper(), make the following call: $checkbox->setDecorators(array(‘ViewHelper’))->render();

    Here you will have both <input> fields, with value of ’1′ for checkbox field and ’0′ for hidden field.

    Reason for this behavior is that $checkbox->render() function prefill options passed to its view helper. Therefore, bypassing ->render() call (by calling ->renderViewHelper()) makes you lose these options.

    note: version of ZF used is 1.8.0