How to hide a Zend_Form_Element, for real.
One thing that blew my mind the other day is how difficult it is to hide a Zend_Form element. Below is a CSS class that I’m going to use to apply to the zend form element.
<style type="text/css"> .hidden { display: none; } </style>
1st wrong method: Defining the class as an option to the element.
Great, I’ve got my CSS class. Now I can just apply that to the element and wahlaa. Wrong. Below is what I tried first.
$this->addElement('text', 'elementName', array( 'label' => 'Label', 'class' => 'hidden' )); /* * the above produces: */ <dt id="elementName-label"> <label for="elementName">Label</label> </dt> <dd id="elementName-element"> <input id="elementName" class="hidden" type="text" name="elementName" /> </dd>
The problem here is that only the input node has gotten the hidden class.
2nd wrong method: re-building the decorators, passing in the class to the element and label.
In order to really hide the element, we need to hide the dt and dd tags. With Zend_Form, if you wan’t further customization of the markup you need to redefine all the decorators for that element. Not only is it not DRY, its a big complicated pain in the ass. Ok, let’s give it a go. This should work right? Wrong.
$this->addElement('text', 'elementName', array( 'label' => 'Label', 'decorators' => array( 'ViewHelper', 'Errors', array('Description', array('tag' => 'p', 'class' => 'description')), array('HtmlTag', array('tag' => 'dd', 'class' => 'hidden')), array( 'Label', array( 'tag' => 'dt', 'class' => 'hidden')) ) )); /* * the above produces: */ <dt id="elementName-label"> <label for="elementName" class="hidden">Label</label> </dt> <dd class="hidden"> <input id="elementName" type="text" name="elementName" /> </dd>
We were able to add the hidden class to the dd element, but the not to the dt element. The label actually took the class and applied it to itself. Not desirable. On top of that, we lost the id on the dd node. Sweet.
The very difficult to come by Correct Method
Not only will getting to this point take alot of time, you get to learn about Decorator Alias’s. If you have multiple decorators of the same type (in this example, HtmlTag) they will overwrite each-other, you need to seperate them with aliases like in the example below. Believe it or not, it takes all this code to apply a class to the dt and dd tags. *3 cheers for Zend_Form!*
$name='elementName'; $this->addElement('text',$name,array( 'label' => 'Label', 'decorators' => array( 'ViewHelper', 'Errors', array('Description',array('tag'=>'p','class'=>'description')), array( array('elementTag'=>'HtmlTag'), array('tag'=>'dd','id'=>$name.'-element','class'=>'hidden') ), array( array('labelTagClose'=>'HtmlTag'), array('tag'=>'dt','closeOnly'=>true,'placement'=>'PREPEND') ), array('Label'), array( array('labelTagOpen'=>'HtmlTag'), array('tag'=>'dt','id'=>$name.'-label','class'=>'hidden','openOnly'=>true,'placement'=>'PREPEND') ) ) )); /* * the above produces: */ <dt id="elementName-label" class="hidden"> <label for="elementName">Label</label> </dt> <dd id="elementName-element" class="hidden"> <input id="elementName" type="text" name="elementName" /> </dd>
Removing The Dt Label On A Display Group In Zend_Form
Another seemingly regular use case with sparse support out there. If your a mark-up perfectionist like me, you’ve no-doubt realized that Zend_Form_DisplayGroup produces markup something like this:
<dt> </dt> <dd> <fieldset> <dl> ... </dl> </fieldset> </dd>
The first thing that occurs to me is the non-need for the dt tag. Here it is the tried and true version:
Removing the dt label for all display groups of a Zend_Form
Use this way in your own extension of Zend_Form, that way all your forms don’t have the useless dt label.
$this->setDisplayGroupDecorators(array(
'FormElements',
array( array( 'tag1' => 'HtmlTag' ), array( 'tag' => 'dl' ) ),
'Fieldset',
array( array( 'tag2' => 'HtmlTag' ), array( 'tag' => 'dd' ) ),
));
Removing the dt label on a per display group basis
This method is handy if you need to set other attributes, say class on the said display group.
$this->addDisplayGroup($elements, 'displayGroupName', array( 'decorators' => array( 'FormElements', array( array( 'tag1' => 'HtmlTag' ), array( 'tag' => 'dl' ) ), 'Fieldset', array( array( 'tag2' => 'HtmlTag' ), array( 'tag' => 'dd', 'class' => 'sweet' ) ), ) ));
If you actually wan’t to set the label inside of the dt, refer to my other post Setting A Label On A Display group in Zend_Form, The Hard And Easy WaY
The following was written during version 1.10.5
Recently I’ve spent a lot of time customizing Zend_Form for use in an form-heavy application. After a little work with this component you will probably find yourself in need of a Display Group; a logical way to group elements together. By Default, your Display Group will have an extra dt tag filled with the special HTML character  , this is coming from Zend_Form_Decorator_DtDdWrapper, so the output of Zend_Form_DisplayGroup ends up like so:
<dt> </dt> <dd> <fieldset> <dl> ... </dl> </fieldset> </dd>
Now let’s say you wan’t to actually put something besides a   inside the dtLabel. You have 2 options:
Setting the label for all Display Groups in a Zend_Form
new Zend_Form(array( 'displayGroupDecorators' => array( 'FormElements', array('HtmlTag' => array('tag' => 'dl')), 'Fieldset', array('DtDdWrapper' => array('dtLabel' => 'My Label'))));
Setting the label on a per Display Group basis
$form->addDisplayGroup($elements, 'nameOfDisplayGroup', array('decorators' => array( 'FormElements', array('HtmlTag' => array('tag' => 'dl')), 'Fieldset', array('DtDdWrapper' => array('dtLabel' => 'My Label')))));
These methods both work and give you an end result of the Display Group with the same decorators, but this time dtLabel‘s value is ‘My Label’. What if you wan’t to set the label without without redefining the decorators each call? You can’t. Unless…
Allow label setting of a Display Group for re-use
- First extend Zend_Form so you can point to your own DisplayGroup class
class My_Form extends Zend_Form { protected $_defaultDisplayGroupClass = 'My_Form_DisplayGroup'; } - Then create your new DisplayGroup class like so:
class My_Form_DisplayGroup extends Zend_Form_DisplayGroup { protected $_label; public function init() { //STORE LABEL $this->_label = $this->getAttrib( 'label' ); $this->removeAttrib( 'label' ); } public function loadDefaultDecorators() { if ($this->loadDefaultDecoratorsIsDisabled()) { return; } $decorators = $this->getDecorators(); if (empty($decorators)) { $this->addDecorator('FormElements') ->addDecorator('HtmlTag', array('tag' => 'dl') ) ->addDecorator('Fieldset') ->addDecorator( 'DtDdWrapper', //PASS LABEL IN HERE array( 'dtLabel' => $this->_label ) ); } } }When the decorator is initialized, you pull the label out of the $attribs array and store it in a local property $this->_label to be later accessed when the decorator is configured.
-
Now you can call this greatly simplified $form->addDisplayGroup:
$form->addDisplayGroup($elements, 'nameOfDisplayGroup', array( 'label' => 'My Label' ));
Hopefully this helps in your Zend_Form journey.
Special Thanks to Christian for helping me with the initial options from my Post on Nabble
Zend Framework is growing up fast. As a developer you are in charge of obtaining the library and keeping it up to date. Zend offers several solutions for obtaining their library but they don’t offer any guidance related to change management and version control. Here is a solution that allows you to manage Zend Framework at the project level, and makes it simple and easy to upgrade to newer versions of Zend Framework. I just upgraded to 1.10.3 in 10 minutes by updating the link and running my unit tests to make sure nothing was broken by the new changes.
Setting Up Zend Framework
svn propset svn:externals \ "Zend http://framework.zend.com/svn/framework/standard/tags/release-1.10.2/library/Zend/" \ library;
Upgrading Zend Framework
svn propedit svn:externals \ "Zend http://framework.zend.com/svn/framework/standard/tags/release-1.10.3/library/Zend/" \ library;
Zend Framework Autoload Demystified
The documentation over @ The Manual isn’t exactly simple, so I’m going to do my best to make autoloading in Zend Framework a breeze.
First, start out by bootstrapping your application w/ this autoload init method. This should be located in /application/Bootstrap.php.
class Bootstrap extends Zend_Application_Bootstrap_Bootstrap
{
protected function _initAutoload()
{
$autoloader = new Zend_Application_Module_Autoloader(array(
'namespace' => 'MyApp',
'basePath' => dirname(__FILE__),
));
return $autoloader;
}
}
Autoloading Forms
For a form named login, make a file called /application/forms/Login.php. Inside that file define a class named MyApp_Form_Login. Now you can instantiate it from anywhere in your app by simply calling new MyApp_Form_Login().
Autoloading Models & DbTables
For a model called user, make a file called /application/models/User.php. Inside that file define a class named MyApp_Model_User. Now you can instantiate it from anywhere in your app by simply calling new MyApp_Model_User().
For a dbtable called user, make a file called /application/models/DbTable/User.php. Inside that file define a class named MyApp_Model_DbTable_User. Now you can instantiate it from anywhere in your app by simply calling new MyApp_Model_DbTable_User().
Upgrading to Zend Framework 1.8
You would think that upgrading to the new Zend Framework would be a piece a cake right? Sorry, no cigar. Let’s get right to it. Most of the changes will occur in your .htaccess file, index.php, and bootstrap.php.
Start by making sure your .htaccess file looks like this:
SetEnv APPLICATION_ENV development RewriteEngine On RewriteCond %{REQUEST_FILENAME} -s [OR] RewriteCond %{REQUEST_FILENAME} -l [OR] RewriteCond %{REQUEST_FILENAME} -d RewriteRule ^.*$ - [NC,L] RewriteRule ^.*$ index.php [NC,L]
Nothing to different here, if anything you lightened this up from Zend’s original QuickStart.
Now let’s check out index.php:
// Define path to application directory if( !defined('APPLICATION_PATH') ) { define('APPLICATION_PATH', realpath(dirname(__FILE__) . '/../application')); } // Define application environment if( !defined('APPLICATION_ENV') ) { define('APPLICATION_ENV', (getenv('APPLICATION_ENV') ? getenv('APPLICATION_ENV') : 'production')); } // Ensure library/ is on include_path set_include_path(implode(PATH_SEPARATOR, array( realpath(APPLICATION_PATH . '/../library'), get_include_path(), ))); /** Zend_Application */ require_once 'Zend/Application.php'; // Create application, bootstrap, and run $application = new Zend_Application( APPLICATION_ENV, APPLICATION_PATH . '/configs/application.ini' ); $application->bootstrap()->run();
So far pretty straightforward. The .htaccess file routes all requests to index.php; which sets the constants for APPLICATION_PATH and APPLICATION_ENV, includes the library folder, and instantiates an instance of Zend_Application. Oh look, a config file is being passed in. lets check that out as well. Here’s an example of mine:
[production] phpSettings.display_startup_errors = 0 phpSettings.display_errors = 0 phpSettings.date.timezone = "UTC" bootstrap.path = APPLICATION_PATH "/Bootstrap.php" bootstrap.class = "Bootstrap" resources.frontController.controllerDirectory = APPLICATION_PATH "/controllers" resources.layout.layoutPath = APPLICATION_PATH "/layouts/scripts" resources.view[] = resources.db.adapter = "pdo_mysql" resources.db.params.host = "localhost" resources.db.params.username = "username" resources.db.params.password = "password" resources.db.params.dbname = "password" resources.db.params.unix_socket = "/var/lib/mysql/mysql.sock" resources.db.isDefaultTableAdapter = true [staging : production] [testing : production] phpSettings.display_startup_errors = 1 phpSettings.display_errors = 1 [development : production] phpSettings.display_startup_errors = 1 phpSettings.display_errors = 1
Notice that the development, testing, and staging configuration sets inherit from production. One thing that was difficult to find in Zend’s documentation was the use of resources.db.isDefaultTableAdapter = true, this enables you to call Zend_Db_Table::getDefaultAdapter() anywhere in your application to grab the adapter. This should make it easy to upgrade any of your model or dbtable classes.
Finally, let’s check out Bootstrap.php:
class Bootstrap extends Zend_Application_Bootstrap_Bootstrap
{
protected function _initAutoload()
{
$autoloader = new Zend_Application_Module_Autoloader(array(
'namespace' => 'Default',
'basePath' => dirname(__FILE__),
));
return $autoloader;
}
protected function _initPresentation()
{
$this->bootstrap('view');
$view = $this->getResource('view');
$view->doctype('XHTML1_STRICT');
$view->headMeta()->setHttpEquiv('Content-Type',
'text/html; charset=utf-8');
$view->headLink()->setStylesheet('/css/shared/reset.css');
$view->headLink()->appendStylesheet('/css/shared/common.css');
$view->headTitle("MyApp | ");
}
protected function _initActionHelpers()
{
Zend_Controller_Action_HelperBroker::addPath(
APPLICATION_PATH."/controllers/helpers"
);
}
protected function _initRoutes()
{
$config = new Zend_Config_Ini (
APPLICATION_PATH . '/configs/routes.ini', 'production'
);
$frontController = Zend_Controller_Front::getInstance();
$router = $frontController->getRouter();
$router->addConfig( $config, 'routes' );
}
}
A couple things to point out here. Obviously, things have changed a bit. This file is no longer a bunch of procedural code setting everything up, its OO baby. The point of this is to group your setup code into logical groups, so you can bootstrap items individually for testing. Any method beginning with _init will be fired when a request is handled. As long as you the database configuration in your application.ini, then there is no need to setup the adapter here. Also to take advantage of the autoloader, make sure your files follow this convention:
/models/Comment.php Default_Model_Comment /modes/DbTable/Comment.php Default_Model_DbTable_Comment /forms/Comment.php Default_Form_Comment
Now you should be able to grab any of these instances by simply instantiating. If you haven’t set up your routes in a config file, I recommend it.
Using Zend_Config with the RewriteRouter
That’s it.
Wish you could have the all the power of a Linux shell on your Windows box without raggedy programs like Cygwin or the weight of a virtual machine? With Microsoft PowerShell, a vamped up CMD, you can.
This guide assumes basic knowledge of the Linux shell but no prior knowledge of PowerShell or CMD is required. If you are running a system prior to Vista, then you will need to download the latest stable of Windows PowerShell
Step 1 – Prepare the “.bashrc” file
Let’s create our profile file which will execute every time we open PowerShell; think of it as your .bashrc file in your home Linux directory. Follow the commands below to get going.
set-executionpolicy unrestricted cd ~/Documents #this will be "cd '~/My Documents'" on systems prior to Windows 7 mkdir WindowsPowerShell notepad $profile
To test that everything went smoothly, simply enter “echo ‘test’” into the file. After saving, close and re-open the shell. If you see “test”, then we are in good condition.
Step 2 – Customize your profile
Now that we have a profile script, we can begin to setup our profile. The first thing I usually do is create various aliases, functions, and variables that assist me in my shell use. Below is an example:
#aliases set-alias vi vim #functions function editpr { vim $profile } #variables $env = Get-ChildItem env: #path $env:PATH+=";C:\Program Files\Zend\ZendServer\share\ZendFramework\bin"
Step 3 – Linux-likeness and resources
Now that we have a full fledged shell in Windows, let’s make ourselves at home. I would suggest adjusting the font and color of your shell ( I use black background with Lucida Console size 12 ) and setting a shortcut for PowerShell ( I use ctrl+shift+` ). Personally, I can’t live without these items below.
Common functions
help -(examples|full) ps -(name "Notepad") service | sort status | ft ls cd clear get-alias get-command | fl | more get-executionpolicy set-executionpolicy (restricted|unrestricted)