zend framework

Custom Zend Validator error messages

The Zend Validator error messages are not the most helpful. Considor the below code for creating a file input:

$this->addElement('file', 'signature', array(
    'validators' => array(
        array('Size', false, 20480), //20k
        array('Extension', false, 'png'),
    ),
    'required' => false,
    'label' => 'Signature',
    'destination' => SIG_PATH,
));

For instance, on the above file input, if you attempt to upload something that is not a PNG file (i.e. photo.JPG, the message will be:

File 'photo.JPG' has a false extension

That’s not very user friendly as it doesn’t give the user any indication of what is an “allowed” file type.

Continue reading

Accessing controller data from a partial viewscript

When using an inline partial viewscript in my form, I sometimes need access to data. I can accomplish this by using a setter and getter with a public function in my form. We’ll use the action “guinness” as the controller action in this example.

application\modules\project\forms\guinness\base.php

protected $_id;

public function setId($id)
{
    $this->_id = $id;
    return $this;
}

public function getId()
{
    return $this->_id;
}

public function getPintCount()
{
    $model = new PubModel();
    return $model->countPints(this->getId());
}

application\modules\project\views\scripts\guinness\page.phtml

<?=$this->render('_partial.phtml');?>

application\modules\project\controllers\GuinnessController.php

<?php
$form = new SomeForm();
$form->setId(123);
?>

application\modules\projects\views\scripts\guinness\_partial.phtml

<?=$this->element->getPintCount();?>

 

This way I can get the content view my connected partials which in essence are a copy of the viewscript.

Seems a long way round, but it keeps everything nicely separated.

 

 

 

Setting up Class Table Inheritance with Doctrine 2.0

Have had some serious problems getting this working, but after a 4 hour head bashing session, we’ve cracked it.

CREATE TABLE inventory(
    inventory_id INT AUTO_INCREMENT,
    discriminator_column VARCHAR(20),
    category VARCHAR(50) NOT NULL,
    part_number VARCHAR(50) NOT NULL,
    PRIMARY KEY (inventory_id),
    KEY category_part_number (category, part_number),
    KEY discriminator_column (discriminator_column)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE inventory_room(
    inventory_id INT NOT NULL,
    rack_limit INT(6),
    room_type VARCHAR(25),
    KEY inventory_id (inventory_id),
    CONSTRAINT inventory_room_key FOREIGN KEY (inventory_id) REFERENCES inventory (inventory_id) 
        ON DELETE CASCADE 
        ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

You have to have a discriminator field so that Doctrine can connect the tables nicely when its joining them.

<?php
namespace Net\Model\Inventory;
use Doctrine\ORM\Mapping as ORM;

/**
 * Inventory entity
 *
 * @ORM\Entity(repositoryClass="Net\Repository\Inventory")
 * @ORM\Table(name="inventory")
 * @ORM\InheritanceType("JOINED")
 * @ORM\DiscriminatorColumn(name="discriminator_column", type="string")
 * @ORM\DiscriminatorMap({"inventory" = "AbstractItem", "inventory_room" = "Room"})
 *
 * @category Net
 * @package  Model
 */
abstract class AbstractItem
{
    /**
     * @ORM\Id @ORM\Column(name="inventory_id") @ORM\GeneratedValue
     * @var int
     */
    protected $inventory_id;

    /**
     * @ORM\Column(type="string")
     * @var string
     */
    protected $category;    

    /**
     * @ORM\Column(type="string")
     * @var string
     */
    protected $part_number;
 }

As you can see in the above class, we have a ORM\GeneratedValue field. This tells Doctrine that this field is an increment field. As this is a one-to-one relationship we do not need one in the inventory_room table as it will be joined on the inventory_id field.

In the next class, this is the child class that extends the abstract. So Doctrine will read the annotations at the top and see that its a joined table using the id field (inventory_id)

<?php
namespace Net\Model\Inventory;
use Doctrine\ORM\Mapping as ORM;

/**
 * Inventory Room entity
 * @ORM\Entity
 * @ORM\Table(name="inventory_room")
 *
 * @category Net
 * @package  Model
 */
class Room extends AbstractItem
{
    /**
     * @ORM\Column(type="string")
     * @var string
     */
    protected $room_type;

    /**
     * @ORM\Column(type="string")
     * @var string
     */
    protected $rack_limit;
}

SVN Externals – how to add them

When creating a Zend Framework site, its always best to keep the Zend library as an external source. This way you can keep the branch up-to-date with the release of Zend with a simple text file.

To access the externals file, navigate to the root of your site:

> cd /var/www/mysite

And add the external to the svn:externals file. I am using the latest version of Zend Framework for this, but you can use any SVN source you like. Note, it has to be available as an SVN repository.

> svn propedit svn:externals .

This will open a text editor.

To enter an external, just enter the local folder to download to, and the source SVN.

destination source

So, if I want my Zend Framework files to be saved in /var/www/mysite/library/Zend :

library/Zend http://framework.zend.com/svn/framework/standard/tags/release-1.11.9/library/Zend/

The first part is the local, second part is the URL of the repository.

Save and close.

Next time you do an update, svn will go and fetch the external files and save them for you.

Other externals are available, such as JQuery, various wikis and other JS sources.

 

 

 

Zend Console – get values passed

When using a CLI script with options, I like to use the Zend_Console.

If my options are as follows:

$console = new Zend_Console_Getopt(
    array(
        'i-s'  => 'test option 1',
        'e'    => 'test option 2')
    );

For instance,

> php myScript.php -i OPTION

To get the “OPTION” string for the -i parameter

$arg = $console->getOption('i');

$arg will now contain the passed option, but if none was passed, it will be NULL

When outlining the available options that can be used with your script, you use the following syntax:

long|short  => description;
test|t => 'Test the script';

You can use,

> php myScript.php -t

or

> php myScript.php --test

to run the -test parameter. You can also pass values, such as an integer or a string:

'test|t=i' => 'Option with required integer parameter';
'test|t-s' => 'Option with optional string parameter'

For more information, refer to the Zend Documentation : http://framework.zend.com/manual/en/zend.console.getopt.introduction.html

Zend_Date – difference between 2 dates

I keep having trouble with this simple calculation! So, here is a little example to get the amount of days between now and the next occurance of July 1st.

//set up the 2 date objects
$now = new Zend_Date();
$next = new Zend_Date();
//we want July 1st
$next->setDay(1)->setMonth(7);
//if we are currently after july this year
if ($now->get(Zend_Date::MONTH) >= 7) {
//we need to work it out til next July
$next->setYear($now->get(Zend_Date::YEAR) + 1);
}
else {
//this july is fine
$next->setYear($now->get(Zend_Date::YEAR));
}
$diff = $next->sub($now)->toValue();
return $diff / 60 / 60 / 24;