Thanks to Zend and their community organizers for the opportunity to do a webinar today.
I have uploaded my slides from the presentation here: Zend Filter Presentation
contains PHP, Web and business/entrepreneurial related content. Please join in the conversation!
Thanks to Zend and their community organizers for the opportunity to do a webinar today.
I have uploaded my slides from the presentation here: Zend Filter Presentation
All the examples I’ve seen for pulling information from subdomains are from the hostname router directly correlating one subdomain as a value to a single controller/action combo. This means they map username.website.com to something that basically looks internally like website.com/user/profile/var1/username. This is cool for simple one off tasks – however, what if you’re creating a multiple controller/action solution? For my example, I’m creating a CMS that will have a shared code base. However, on every page, I need to know exactly which site this is.
Enter Chaining!
So far, all the examples have shown how to chain a hostname route to a single other route. Like I mentioned, this solves the singular subdomain->action connection. However, now I need to apply it to all of my routes.
In my example, I’m going to make sure that the following code is at the very end of adding all of my other standard routes. If someone adds a route AFTER this code, it will not work correctly for their routes.
Use the following code:
1 2 3 4 5 6 7 8 | $router = Zend_Controller_Front::getInstance()->getRouter(); $hostnameRoute = new Zend_Controller_Router_Route_Hostname(":sitename.example.com"); $router->addDefaultRoutes(); foreach ($router->getRoutes() as $key=>$route) { $router->addRoute('hostname' . $key, $hostnameRoute->chain($route)); } |
First, the router is retrieved again. Next, the hostname route is created. In this case, our domain is example.com. I want to have a parameter called sitename in my controllers. Next, I force the router to add its default routes right now. Normally this is done after custom routes. Finally, each route that now exists, the default routes, the custom ones you’ve written, etc, are all looped through. A new route is added which is basically named after that route with the prefix of ‘hostname’. The route is a chained version of the original with the hostname.
Now, when visiting site1.example.com/blog/add, the parameters array in the controller will be:
'sitename'=>'site1', 'controller'=>'blog', 'action'=>'add' 'module'=>'default'
There are two ways of working with Zend Framework as a library in your project. These are including it in your project repository and using a shared copy on the server (like PEAR). Let us discuss both:
The first method is to include the Zend Framework library folder in your zend framework project’s library folder (uh….). So, for each project on your server that is built on Zend Framework, the following path has a copy of Zend Framework: /root/to/your/app/library/Zend. This means each project has at least the entire size of the Zend Framework in it. Pros/Cons?
Like PEAR, Zend Framework can be installed on the server in a shared location. You may install your Zend Framework Library folder into a different path, for example: /root/to/shared/code/Zend. Then, your PHP has to be configured to have that in its include path. Pros/Cons?
Currently, I’m going with including it each project as a point of preference. I think the risks outweigh the possible time/storage savings. So, what are your thoughts?
For some reason, I just had the most horrible time making sure that my connection from my Zend Framework code was speaking UTF8 at my database. Here are the key things to remember that I learned:
Ok first thing’s first. Create the database with the proper collation:
1 | CREATE SCHEMA `mydatabasename` DEFAULT CHARACTER SET utf8; |
Next, define your tables with UTF8 charset:
1 | CREATE TABLE `mynewtable` (`a` INT NULL ,`b` INT NULL) ENGINE = InnoDB DEFAULT CHARACTER SET = utf8; |
Finally, if configuring your PDO/MySQL connection in application.ini, after defining the connection parameters, as I have, add the last two lines
resources.db.adapter = "pdo_mysql" resources.db.params.host = "localhost" resources.db.params.username = "user" resources.db.params.password = "password" resources.db.params.dbname = "mynewtable" resources.db.isDefaultTableAdapter = true resources.db.params.charset = "utf8" resources.db.params.driver_options.1002 = "SET NAMES utf8;"
I never had a chance to track down the reasons “why” this was happening – so if anyone has any input, that would be great. But now I add this to all of my projects just to force it.
Zend Framework has a few hooks with the Firebug browser plugin (with the firePHP add-on). The two that I use are writing logs to the console and profiling of database connections.
First thing’s first: Make sure to only enable these settings in your non-production environments.
One of the most helpful things I do for my database setup is initialize the Zend_Db profiler with firebug in my application.ini file. It is important to have this under the development section and nowhere else. Check out this snippet of my application.ini file:
[development : production] resources.db.params.profiler.enabled = "true" resources.db.params.profiler.class = "Zend_Db_Profiler_Firebug" ...
I don’t like to check logs while I’m developing. I’d rather have all of these alerts in my face. Luckily, Zend Framework allows a firebug logger to do this for me. In my bootstrap.php file, I will create a method similar to this:
1 2 3 4 5 6 7 8 9 | protected function _initLogs() { $logger = new Zend_Log(); if ($this->getEnvironment() != 'production') { $writer = new Zend_Log_Writer_Firebug(); } $logger->addWriter($writer); return $logger; } |
With this code, your log-able items can retrieve this bootstrap resource and it will write the messages right to the console. (Side note: Most of my applications actually have another part to that If statement where they define the production logging system including setting priorities).
Do you have any creative uses for Firebug with Zend Framework?
Through reading a few blog posts over the last year and my own trial and error, I’ve developed a way of using the flashMessenger Helper in ZF that works out really well for me. (Note: if anyone knows the original blog post that I got some of the view helper from, please comment!).
Now, we’re going to change the way we assign messages in the controller. Make an array of the message with a key of the type, and a value of the message. You may want to use ‘success’ and ‘failure’: in some controller…
1 |
Create the following view helper. I placed mine here: application/views/helpers/FlashMessages.php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | class Zend_View_Helper_FlashMessages extends Zend_View_Helper_Abstract { public function flashMessages() { $messages = Zend_Controller_Action_HelperBroker::getStaticHelper('FlashMessenger')->getMessages(); $output = ''; if (!empty($messages)) { $output .= '<ul id="messages">'; foreach ($messages as $message) { $output .= '<li class="' . key($message) . '">' . current($message) . '</li>'; } $output .= '</ul>'; } return $output; } } |
The output is initially blank. This is because we will always ‘blindly’ call this in our layout later. Then, the messages are retrieved from the flash messenger using the getStaticHelper method to retrieve the FlashMessenger helper (and call its getMessages() method). If it has content, output is appended with a UL with an ID of messages (this is for css styling later). Then, each message is looped through and added to an LI element. The ‘type’ is the class of that element, and the message is the content. (Note: since this is an array of single arrays where neither the key nor the value is known, that is the reason to use key() and current()). Finally, output is updated with the closing UL tag.
I technically put this call in my layout towards the top of my content:
1 | echo $this->flashMessages(); |
I also modify my CSS to have styling of green for the #messages li.success and red for #messages li.failure.
One of the steps to install PHPUnit is to execute the following pear commands:
1 2 | pear channel-discover pear.phpunit.de pear install phpunit/PHPUnit |
However, after doing that, I got the following error: no release available for package pear.phpunit.de/PHPUnit – and the install failed.
I decided to execute a remote-list command – it was a thought that maybe I could see if maybe my phpunit declaration was wrong – I was just grasping at straws…
1 | pear remote-list -c phpunit |
This finally gave me a worthwhile error! “The value of the config option cache_dir (/tmp/pear/cache) is not a directory and attempts to creat the directory have failed”
So, I finally was successful after the following two commands:
1 2 | mkdir /tmp/pear/cache pear install phpunit/PHPUnit |
Moral of the story: check to make sure PEAR has a cache directory available if you can’t install a PEAR package.
Google Charts has a QR code generation service (here are the details). I decided that I wanted to create my own ZF View Helper to display these on my pages. This version that I am going to show just returns the properly formatted URL for the charts API. The view must create the img tag around it.
Place the following code in your view helpers location. For example… application/views/helpers/GoogleQRCode.php.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | class Zend_View_Helper_GoogleQRCode extends Zend_View_Helper_Abstract { public function googleQRCode($data, $width = 100, $height = 100) { $url = 'https://chart.googleapis.com/chart?'; $params = array( 'cht'=>'qr', 'chs'=>(int)$width . 'x' . (int)$height, 'chl'=>$data ); $url .= http_build_query($params); return $url; } } |
First thing is the function declaration. It will accept some data to encode. By default, the width and height are 100px. This can be overridden with the helper call. Next, the URL for the Google charts API is defined. Notice that this version is https – just in case its used on SSL websites. Next, the parameters to the API are built. The ‘cht’ or chart type is ‘qr’. The chart size or ‘chs’ is the integer width by the integer height. Finally, the ‘chl’ value is the data. Finally, the URL is appended with the value of the results of http_build_query() of the url parameters. Finally, the URL is returned from the method.
IMPORTANT NOTE: In the spec, it says that the data should be url encoded. The view helper is not doing that when it creates the parameter array. This is handled by http_build_query.
To use this in your view, you may have the following code: application/views/scripts/index/index.phtml
1 2 3 4 | echo '<h2>Find Me Online</h2>'; echo '<img src="'; echo $this->googleQRCode('http://aaronsaray.com/contact'); echo '">'; |
Future options: At some point if I tend to use this more often, I might replace this entire view helper with a more model based application. The view helper will still call the model, but the model will handle retrieving and caching these QR codes. If the Google Charts API is not responding, previously generated QR codes will still be available that way!
I will be presenting at the WAIMM Email Marketing Software meetup today. I plan to cover the basics of Mailchimp for comparison to other services like Constant Contact.
Download the presentation powerpoint here: Mailchimp Overview Presentation
Running a test, I ran into this error:
Zend_Session_Exception: Session must be started before any output has been sent to the browser; output started in /usr/share/php/PHPUnit/Util/Printer.php/173
In order to solve that, I added a line calling ob_start() to my test bootstrap file.
However, there is a better way!!
Instead, add the following line:
1 | Zend_Session::$_unitTestEnabled = true; |
This works flawlessly.