Tag Archive: zend


Sometimes, you’ll want the same form in more than one place in your application, however occasionally, that means your forms look terrible! However you can specify a different view script to use (I put mine in a forms subdirectory):

$this->addDecorators(array(
    array('ViewScript', array('viewScript' => 'view_folder/different-looking-form.phtml'))
));

And the bit that confdused me for a while, accessing the form in that view is strangle called $this->element:

<?= $this->element; ?>

Of course, as you may know, you don’t have to render the form like that, which is kind of the point of this:

<?php
$form = $this->element;
$supply = $form->getSupply();
$fueltype = $form->getFueltype();

?>

<form id = "<?=$form->getAttrib('id') ?>"
    name = "<?=$form->getName() ?>"
    method = "<?=$form->getMethod(); ?>"
    enctype = "<?=$form->getEnctype(); ?>"
    >
    <dl class="zend_form">

        <dt><label>Supply / Meter</label></dt>
        <dd><?=$supply->getMeterNumber() ?></dd>

        <dt><label>Fuel Type</label></dt>
        <dd><?=$fueltype->getFueltype() ?></dd>

        <dt><label>Description</label></dt>
        <dd><?=$supply->getDescription() ?></dd>

    <?php
    foreach ($form->getElements() as $element)
    {
        echo $element;
    }
    ?>
    </dl>
</form>

Sorted! No need to encase your form in more divs and mess around with CSS! 🙂

Advertisements

Expanding upon my abstract DB class that auto creates Zend_Paginators on demand, I thought it was about time I did something regarding automatically sorting the records returned.

First thing I did was go in and edit my db base class (need a reminder? https://delboy1978uk.wordpress.com/2014/06/30/auto-paginator-with-zend_db_table/), adding a sort_field property, a setSortField() method, and a little if statement in our getResult() method :

    /** @var string $sort_field */
    protected $sort_field = null;
    /**
     *  For instance 'date_added DESC'
     *  @param int $no
     *  @return $this
     */
    public function setSortField($sort_and_direction)
    {
        $this->sort_field = $sort_and_direction;
        return $this;
    }
    /**
     * @param Zend_Db_Select|string $select
     * @return \Zend_Db_Table_Rowset_Abstract|Paginator
     */
    public function getResult($select)
    {
        if(is_string($select))
        {
            $select = $this->select()->where($select);
        }
        if($this->sort_field)
        {
            $select->order($this->sort_field);
        }
        if($this->paginator_flag == true)
        {
            return $this->getPaginator($select);
        }
        return $this->fetchAll($select);
    }

Now we have that, we can sort any queries like so:

        // Get the page number
        $page = ($this->getRequest()->getParam('page')) ?: 1;
                
        // Set pagination
        $db->setPaginatorFlag(true);
        $db->setNumPerPage(30);
        $db->setPage($page);
        
        // Get sort field
        $sort = $this->getRequest()->getParam('sort');
        $dir = $this->getRequest()->getParam('dir');
        
        // Set the sort
        $db->setSortField($sort.' '.$dir);

Again, in your DB class method, make sure it calls $this->getResult(); and not fetchAll().

Anyway, thats only one half of the equation, what we need is sort links! I create a view helper for this, which basically calls the url view helper, but with additional search capabilities. In the Bootstrap (as you’ll know), we define our routes as such:

$router->addRoute(
    'lead-assessor-view-supply',
    new Zend_Controller_Router_Route(
        '/lead-assessor/view-supply/:orgid/:id/:page/:sort/:dir',
         array(
            'controller' => 'lead-assessor',
            'action' => 'view-supply', 
            'page' => 1, 
            'sort' => 'date_from', 
            'dir' => 'DESC'
         )
      )
);

As you can see, I have added sort and dir in addition to page.  To get the links working, send the page, sort, and dir variables to the view, and in the view, instead of calling $this->url(blahblah); we will call our own view helper, sortLinks(); Here’s the class:

<?php 

class ESOS_View_Helper_SortLinks extends Zend_View_Helper_Abstract
{
    /** 
     *  Pass in a route name, and an array of any params which are the same for all the sort links
     *  @param string $route_name
     *  @param array $params
     *  @param string $field_name
     *  @param string $sort_field
     *  @param string $sort_dir
     *  @param string $field_label
     *  @param string $classes
     *  @return string
     */
    public function sortLinks(array $params,$route_name,$field_name,$field_label, $classes = null)
    {
        // Set the current sort field
        $current_sort_field = isset($params['sort']) ? $params['sort'] : 'ASC' ;
        
        // Set the Icon
        $icon = $this->view->sortIcon($field_name,$current_sort_field,$params['dir']);
        
        // Set params
        $params['sort'] = $field_name;
        $params['dir'] = $this->view->sortDir($field_name, $current_sort_field, $params['dir']);
        
        // Build the HTML
        $link = '<a href="';
        $link .= $this->view->url($params,$route_name);
        $link .= '" class="';
        $link .= $classes;
        $link .= '">';
        $link .= $icon;
        $link .= $field_label;
        $link .= '</a>';
        
        // Return the HTML
        return $link;
    }
}

Almost there! You’ll see it is calling another two view helpers, sortIcon and sortDir:

<?php

class ESOS_View_Helper_SortDir extends Zend_View_Helper_Abstract
{
    public function sortDir($field_name, $current_sort_field, $dir)
    {
        if($field_name == $current_sort_field)
        {
            switch($dir)
            {
                case 'ASC':
                    $dir = 'DESC';
                    break;
                case 'DESC':
                default:
                    $dir = 'ASC';
                    break;
            }
        }
        return $dir;
    }
}
<?php

class ESOS_View_Helper_SortIcon extends Zend_View_Helper_Abstract
{
    public function sortIcon($field_name, $current_sort_field, $dir)
    {
        if($field_name == $current_sort_field)
        {
            switch($dir)
            {
                case 'ASC':
                    $icon = '<i class="fa fa-caret-up"></i>&nbsp;';
                    break;
                case 'DESC':
                default:
                    $icon = '<i class="fa fa-caret-up"></i>&nbsp;';
                    break;
            }
        }
        else 
        {
            $icon = null;
        }
        return $icon;
    }
}

These just figure out which direction of sort the link will generate. The Icons are from Font Awesome, but feel free to use anything you like!

Tying it all together, in your view, define an array of any parameters that you will pass into each sort link (sort, and dir should always be in there, page if using the paginator):

    // Common params for the sortLinks
    $params = array(
        'orgid' => $this->org->getId(),
        'page' => $this->page,
        'sort' => $this->sort,
        'dir' => $this->dir,
    );

At the top of your table where you want your clickable sort links, call:

<?= $this->sortLinks($params,'portfolio-admin-users','name',$this->t('Organisation')); ?>

Sorting By Price

Sorting By Status

This will save a LOT of farting around in the future! Have fun! 🙂

Make your pagination EASY! Whether using Zend Framework’s MVC, or just the library classes!

By now you might have read by now that half the folk that were using Zend_Paginator have been using it wrong.  They would get their rowset from the table, and then create a paginator and pass in the rowset. Sure, it works, but you have just fetched ALL the rows first, and Paginator displays only the records in question. That is a huge waste of resources!

What SHOULD be happening is that you pass a select() object to the paginator, to which it will figure out the offsets and limits.

Anyway, pretty much all my db classes were returning either rowsets or rows depending on the method. What i needed was for it to return the select. So I had an idea. Auto pagination!

Rather than your db classes extending Zend_Db_Table, we will extend our own abstract class which will  itself extend Zend_Db_Table.

Our class will have a couple of properties;  a flag for pagination on/off, the page number, and the num per page. It will also have a few  methods, as you can see below.

<?php

namespace AA\Repository;

use Zend_Db_Table_Abstract as Table;
use Zend_Db_Table_Select as Select;
use Zend_Paginator as Paginator;
use Zend_View_Helper_PaginationControl as PaginationControl;

abstract class AbstractRepository extends Table
{
 /** @var bool */
 private $paginator_flag = false;
 /** @var int */
 private $page = 1;
 /** @var int */
 private $num_per_page = 30;

 /**
 * @param bool $bool
 * @return $this
 */
 public function setPaginatorFlag($bool)
 {
 $this->paginator_flag = $bool;
 return $this;
 }

 /**
 * @param int $no
 * @return $this
 */
 public function setPage($no)
 {
 $this->page = $no;
 return $this;
 }

 /**
 * @param int $no
 * @return $this
 */
 public function setNumPerPage($no)
 {
 $this->num_per_page = $no;
 return $this;
 }

 /**
 * @param Select $select
 * @return Paginator
 */
 private function getPaginator(Select $select)
 {
 PaginationControl::setDefaultViewPartial('NavControls.phtml');
 $paginator = Paginator::factory($select);
 $paginator->setCurrentPageNumber($this->page);
 $paginator->setItemCountPerPage($this->num_per_page);
 return $paginator;
 }

 /**
 * @param Select $select
 * @return \Zend_Db_Table_Rowset_Abstract|Paginator
 */
 protected function getResult(Select $select)
 {
 if($this->paginator_flag == true)
 {
 return $this->getPaginator($select);
 }
 return $this->fetchAll($select);
 }
}

(If you aren’t using namespaces in your code, you can tweak it to the old style.)

The setPaginatorFlag($bool) turns paging on or off. setPage($no) and
setNumPerPage($no) are self explanitory. getPaginator(Select $select) returns a paginator from the select object.  The interesting method is getResult(Select $select). It checks wether we asked for a paginator. If so it calls getPaginator, if not it does a plain fetchAll.

Have a look at a simple DB Class which now uses the auto paginator:

namespace AA\Repository;


class Competitors extends AbstractRepository
{
 protected $_name = 'branch_competitors';
 protected $_rowClass = 'AA\Entity\Branch\Competitors';


 public function getCompetitors($bid)
 {
 return $this->fetchRow('bid = '.$bid);
 }

 public function getAllCompetitors()
 {
 $select = $this->select()
 ->order('bid DESC');
 return $this->getResult($select);
 }
}

The interesting parts here are the extends AbstractRepository, and return $this->getResult($select). We now use getResult so that it can decide whether to give you a rowset or a paginator.

In your views, you can now just echo it out to give you your paginator! (Of course, you will have your pagination view partial set! see manual for details)

However if you are using Zend Framework libraries without using the MVC component, we can still use Zend Paginator without concerning ourselves with Zend_View etc. I created a view helper class with a static render method, accepting the paginator and the current url:

namespace AA\View\Helper;

use Zend_Paginator;


class Paginator 
{
 public static function render(Zend_Paginator $paginator,$url)
 {
 $url = parse_url($url);
 parse_str($url['query'],$result);
 $class = null; //for now
 if ($paginator->getPages()->pageCount)
 {
 $html = '<div class="pagination"><ul>';
 if (isset($paginator->getPages()->previous))
 {
 $result['page'] = $paginator->getPages()->first;
 $query = http_build_query($result);
 $html .= '<li>
 <a class="'.$class.'" id="first" href="'.$url['path'].'?'.$query.'">
 first
 </a>
 </li>';
 }
 else
 {
 $html .= '<li class="disabled"><a href="#">first</a></li>';
 }
 if (isset($paginator->getPages()->previous))
 {
 $result['page'] = $paginator->getPages()->previous;
 $query = http_build_query($result);
 $html .= '<li>
 <a class="'.$class.'" id="last" href="'.$url['path'].'?'.$query.'">
 previous
 </a>
 </li>';
 }
 else
 {
 $html .= '<li class="disabled"><a href="#">previous</a></li>';
 }
 if (isset($paginator->getPages()->next))
 {
 $result['page'] = $paginator->getPages()->next;
 $query = http_build_query($result);
 $html .= '<li>
 <a class="'.$class.'" id="next" href="'.$url['path'].'?'.$query.'">
 next
 </a>
 </li>';
 }
 else
 {
 $html .= '<li class="disabled"><a href="#">next</a></li>';
 }
 if (isset($paginator->getPages()->next))
 {
 $result['page'] = $paginator->getPages()->last;
 $query = http_build_query($result);
 $html .= '<li>
 <a class="'.$class.'" id="last" href="'.$url['path'].'?'.$query.'">
 last
 </a>
 </li>';
 }
 else
 {
 $html .= '<li class="disabled"><a href="#">last</a></li>';
 }
 $html .= '</ul></div>';
 }
 else
 {
 $html = null;
 }
 return $html;
 }
}

So on a plain ol’ PHP page (that’s able to autoload the classes, if not, require them or look into composer), here’s all you would need (my current url in this example is “/?id1=-competitors”):

$page = ($_GET['page']) ? filter_input(INPUT_GET, 'page', FILTER_SANITIZE_NUMBER_INT) : 1;
//set pagination on for this query
$db->setPaginatorFlag(true)
   ->setPage($page)
   ->setNumPerPage(30);
//get paginator/rowset
$competitors = $db->getAllCompetitors();
//show paginator
echo \AA\View\Helper\Paginator::render($competitors,'/?id1=competitors');
foreach($competitors as $competitor)
{
    //row stuff here
}

Awesome! Now you need never again have to muck around with paginators, whether using Zend Frameworks MVC or not! Have fun!


							

Apigility rocks! It’s still in its early beta days (and hence a little buggy at times), but it’s WELL worth playing with now for building your API’s!

Anyway, you can create code connected and db connected services. Db connected REST services pretty much give you the auto CRUD functionality, but it would be nice to have some where, and order clauses!

This feature should be ready for version 1.2, but in the meantime, lets override it mannually!

You will notice in your Rest/ServiceName folder (in my particular case, Agents), that it has auto generated an AgentsCollection and an AgentsEntity PHP file.

We will create our own Resource Class which will extend the DBConnectedResource. So I created AgentsResource.php :

 

 <?php

namespace Allagents\V1\Rest\Agents;
use ZF\Apigility\DbConnectedResource;
use Zend\Paginator\Adapter\DbTableGateway as TableGatewayPaginator;

class AgentsResource extends DbConnectedResource
{
 public function fetchAll($data = array())
 {
 // WHERE CLAUSE
 $where = '';
 foreach($data->where as $clause)
 {
 $where .= $clause.' AND ';
 }
 //chop off the last AND
 $where = substr($where,0,-4);

 // ORDER CLAUSE
 $order = '';
 foreach($data->order as $clause)
 {
 $order .= $clause.' , ';
 }
 //chop off the last comma
 $order = substr($order,0,-2);

 // GROUP CLAUSE
 $group = '';
 foreach($data->group as $clause)
 {
 $group .= $clause.' , ';
 }
 //chop off the last comma
 $group = substr($group,0,-2);

 // HAVING CLAUSE
 $having = '';
 foreach($data->having as $clause)
 {
 $having .= $clause.' AND ';
 }
 //chop off the last AND
 $having = substr($having,0,-4);
 $adapter = new TableGatewayPaginator($this->table,$where, $order, $group, $having);
 return new $this->collectionClass($adapter);
 }
}

Ok, now we have to tell ZF2 to use our resource class instead of the default. As always, ZF2 modules are mega customisable, and usually involves tweaking your module.config. Apigility is no different, so jump into your module folder and open the module.config.php. We are adding one line to our DBConnectedResource. Find the section ‘zf-apigility’ => ‘db-connected’ and you will see your service’s entry. We add an array key like so; ‘resource_class’ => ‘Allagents\\V1\\Rest\\Agents\\AgentsResource’,

'zf-apigility' => array(
 'db-connected' => array(
 'Allagents\\V1\\Rest\\Agents\\AgentsResource' => array(
 'adapter_name' => 'DBAdapter',
 'table_name' => 'agents',
 'hydrator_name' => 'Zend\\Stdlib\\Hydrator\\ArraySerializable',
 'controller_service_name' => 'Allagents\\V1\\Rest\\Agents\\Controller',
 'entity_identifier_name' => 'aid',
 'resource_class' => 'Allagents\\V1\\Rest\\Agents\\AgentsResource',
 ),
 ),
 ),

Lastly, we need to whitelist the query parameters that we use, otherwise they will not appear in the HAL links!

Again, in the module.config.php, in the section ‘zf-rest’, we add an array defining the whitelisted parameters:

'zf-rest' => array(
 'Allagents\\V1\\Rest\\Agents\\Controller' => array(
 'listener' => 'Allagents\\V1\\Rest\\Agents\\AgentsResource',
 'route_name' => 'allagents.rest.agents',
 'route_identifier_name' => 'agents_id',
 'collection_name' => 'agents',
 'entity_http_methods' => array(
 0 => 'GET',
 1 => 'PATCH',
 2 => 'PUT',
 3 => 'DELETE',
 ),
 'collection_http_methods' => array(
 0 => 'GET',
 1 => 'POST',
 ),
 'collection_query_whitelist' => array(
 0 => 'where',
 1 => 'order',
 2 => 'having',
 3 => 'group',
 ),
),


To test it is working, call your URL (in my case /agents) and you should see the normal expected results. Now test with a query sting. I made a little script to build the query up:

<?php

$query = http_build_query(array(
 'where' => array(
 'name LIKE "A%"',
 ),
 'order' => array(
 'name asc',
 ),
 'group' => array(

 ),
 'having' => array(

 ),
));

echo $query.'<br />';

Which output:
where%5B0%5D=name+LIKE+%22A%25%22&order%5B0%5D=name+asc
So I called: /agents?where%5B0%5D=name+LIKE+%22A%25%22&order%5B0%5D=name+asc
You should have your filtered results, with HAL links in the JSON, like so!

{
“_links”: {
“self”: {
“href”: “http://api.allagents.del/agents?where%5B0%5D=name%20LIKE%20%22A%25%22&order%5B0%5D=name%20asc&page=1&#8221;
},
“first”: {
“href”: “http://api.allagents.del/agents?where%5B0%5D=name%20LIKE%20%22A%25%22&order%5B0%5D=name%20asc&#8221;
},
“last”: {
“href”: “http://api.allagents.del/agents?where%5B0%5D=name%20LIKE%20%22A%25%22&order%5B0%5D=name%20asc&page=44&#8221;
},
“next”: {
“href”: “http://api.allagents.del/agents?where%5B0%5D=name%20LIKE%20%22A%25%22&order%5B0%5D=name%20asc&page=2&#8221;
}
},
“_embedded”: {
“agents”: [
{
“aid”: “2842”,
“etc”:”etc!”

Have fun! Maybe I could even get this into the actual Apigility code by sending them a Pull Request! (Probably not though lol, I’m sure they’ll figure a better way of dealing with the query params than passing RAW SQL portions haha!)

As a Zend Framework 1 user I loved the simplicity of the class naming convention, being Folder_Subfolder_ClassName. However as you probably know, these class names get really quite long! The latest PHP as you already know uses namespaces and allows for shorter classnames that wont clash with each other. Now I have added an API to my website using the incredible Apigility (http://apigility.org) which was built in Zend Framework 2, I thought it would be nice to upgrade my existing classes to autoload PSR-0 style, so I can eventually migrate easily across.

First thing then, you need composer installed. If you’ve been following my blog, or using any other vendors packages, you’ll already have it in your project.

In ZF1, the library folder was where you would keep your different modules/packages/classes. I have a library called TTB. So in the TTB folder, create an src folder, and another TTB folder in there (this is a quirk of PSR-0, but trust me). In that folder, recreate your classes. Changes aren’t very difficult:

<?php
namespace TTB\Form;
use TTB\Form\Element;

class Contact extends \Zend_Form
{
    //etc
}

The line TTB_Form_Contact extends Zend_Form is shortened by way of the namespace line at the top to just become Contact, and the Zend_Form gets a backslash in front of it as it is in the global namespace. You also specify use  to import any other classes into the namespace. Now we can call Textbox instead of Element\Textbox or TTB\Form\Element\Textbox.

You probably know all this stuff anyway! The point is, to get it autoloading in your project!

So in your index file of your ZF1 project, require once vendor/autoload.php. And in your composer.json, add the following:

"autoload": {
     "psr-0": {
         "TTB" : "application/library/TTB/src/"
     }
 }

Finally, run composer dump-autoload in the terminal from your site root, and this will generate the classmap. You are now ready for PSR-0 compliance! Now you just need to spend all day refactoring! It’ll be worth it when you take your old project to a new framework!  😉

If you checked my last post, you will have read about how to get all your old ZF1 classes autoloading in your new shiny ZF2 project. However, the DB settings from your application.ini won’t have been set, and so you’ll get a 500 response with  No Db Adapter. Not a problem. We just create the db adapter ourselves and tell Zend_Db that it is the default.

I’ve put this in the ZF2 index.php just before the last line, Zend\Mvc\Application::init($appConfig)->run();

//Set up ZF1 DB
$params = array(
 'host' => '127.0.0.1',
 'username' => 'xxx',
 'password' => 'xxx',
 'dbname' => 'xxx'
);
$adapter = Zend_Db::factory('Pdo_Mysql',$params);
Zend_Db_Table_Abstract::setDefaultAdapter($adapter);

Now your autoloading ZF1 DB classes wont freak out, and should connect no problem!

I’ve started using Apigility for building my API for my mobile app of my site! It’s incredible, you have to try it!

Anyway, I wanted to be able to load my existing code into ZF2 so I didn’t have to reinvent the wheel.

My API is running on a subdomain in an api sub folder within the main project. In the api folder, I made a folder called library. Then I symlinked my Zend and other folders from my ZF1 project into it (this may not have been necessary, but I didn’t want ../.. relative link type stuff in my composer.json)

:~/www/site/api/library$ ln -s ../../application/library/Zend Zend
:~/www/site/api/library$ ln -s ../../application/library/ZendX ZendX
:~/www/site/api/library$ ln -s ../../application/library/TTB TTB
:~/www/site/api/library$ ln -s ../../application/library/AA AA

Next you need to do is tell composer.json about your libraries.

 "autoload": {
 "psr-0": {
 "AA_": "library/",
 "Zend_": "library/",
 "ZendX_": "library/"
 }
 },
 "include-path": [
 "library"
 ]

Finally get composer generating autoload files. Type in:

~/www/site/api$ composer dump-autoload
Generating autoload files

And thats it! You should now be able to call things like:

$awesome = new Zend_Pdf();
$old_skool = new AA_Old_Skool_Class();

Yay!

This look familiar?

PHP Warning:  PHP Startup: memcached: Unable to initialize module
Module compiled with module API=20090626
PHP    compiled with module API=20100525
These options need to match

I don’t know about you, but i like to be up to date! My PHP is on 5.5, and I had to install some modules. But sometimes, old versions can rear their ugly head, and cause all manner of grief. Package managers do a good job to take care of all this for you, but sometimes they just don’t work. Leaving you to compile yourself! So lets do it! I’m going to install memcached, and then the imagick libraries (now i know what i’m doing!)

I’m doing this on a CentOS 6 server, but as we are doing the old skool way of compiling etc, this should work on any other flavour of Linux, or indeed Mac OS X.

First step is to download your .tar.gz  then unzip it with tar -zxvf file.tar.gz and change into the folder.
Bring up a web page displaying your servers php.ini. You are looking for the version of PHP API, and the extension_dir.
In your terminal, cd into the module source code folder, and type phpize.

If when you check the API versions , they are different from your php.ini, then an old version of php is being used in the terminal, and your module will not work! In this case, you need to get it to use the correct phpize.

type 'which phpize' to find out where the offending file is. (mine was /usr/bin/phpize)

My PHP appeared to be in /usr/local, so I tried running /usr/local/phpize. The API’s matched. So then I did the following:

mv /usr/bin/phpize /usr/bin/phpize-old
 ln -s /usr/local/bin/phpize /usr/bin/phpize

Half way there! We need to do the same for php-config

mv /usr/bin/php-config /usr/bin/php-config-old
 ln -s /usr/local/bin/php-config /usr/bin/php-config

Now you have done that, installation should be trivial, and work as per loads of tutorial/instrruction pages on the web.

./configure
 make
 make install

Finally edit your php.ini and add ‘extension = memcached.so’ (or whatever module you compiled), and restart your apache server!

EDIT : you may need to run ‘phpize –clean’ if it is still compiling with the older stuff from within the modules source folder

AKA more utf-8 vs latin pain and woe.

Ok. Some of you may have read my earlier post where I thought zend form was screwing up, when in actuality is the IDE. Well the fun didn’t stop there. So to spare you the pain and anguish etc, here’s what you do.

Make sure your database is UTF-8, and any fields have utf8_general_ci
In your application.ini - resources.db.params.charset = utf8
In your application.ini - resources.view.encoding = "UTF-8"
In your layout phtml head - <meta charset='utf-8'>

We should all be smiling happy now!

Here’s a poser for you. Open up a controller and its view and try this:

Controller:

$this->view->utf8 = 'Si Señor!';
 $this->view->html = 'Le Cr&eacute;pe';
$btn1 = new Zend_Form_Element_Button('btn1');
 $btn1->setLabel($this->view->utf8);
$btn2 = new Zend_Form_Element_Button('btn2');
 $btn2->setLabel($this->view->html);
$this->view->btn1 = $btn1;
 $this->view->btn2 = $btn2;

View:

<?php echo 'utf-8: '.$this->utf8.'<br />'
 'html: '.$this->html.'<br />'
 'btn1: '.$this->btn1.'<br />'
 'btn2: '.$this->btn2; ?>

Output:

utf8: Si Se�or!
html: Le Crépe
btn1: ()
btn2: (Le Cr&eacute;pe)

the (buttons) render, but:
the first one is blank (kind of expected as the utf8 variable doesn’t display either)
the 2nd one displays a label, and the html variable worked as we knew it would, however the &acute; entity is displaying in the label.

what does this mean?
does it mean that! the Zend_Form_Element_Button has doubly encoded it?
it must have sent Cr&amp;eacute;pe to the browser!

This is busting my chops! Send it unencoded and it fails to render the label, and send it encoded and it gets encoded twice 😐

Screen Shot 2013-02-06 at 22.02.22

UPDATE: You’ve checked character encoding in your code, mac textedit, the db, the templates, the form decorators,  the form filters, the forums, irc, but guess what? you forgot the IDE.