Archive for June, 2012


At least some things are nice and uncomplicated! Installing Doctrine is simple:

sudo pear channel-discover pear.doctrine-project.org
sudo pear channel-discover pear.symfony.com 
sudo pear install -a pear.doctrine-project.org/DoctrineORM-2.2.2
sudo pear install  pear.doctrine-project.org/DoctrineSymfonyConsole
sudo pear install  pear.doctrine-project.org/DoctrineSymfonyYaml

And if all went to plan you should have the command line interface (CLI)

doctrine -V

Lastly just copy the Doctrine and vendor folders into you php library on the include path.

When trying to upgrade php in XAMPP, I ran into the problem faced when you use an all in one solution for your LAMPP development, i.e.. you’re stuck with whatever versions have been compiled in. So instead, I decided to take advantage of the built in Apache thats ships with the MacBook Pro. Now, we’re going to set up MySQL. Head over to their website and download the 64 bit package. Mount the disk image and run the installer. There’s also a preference pane installer, which handily starts and stops mysqld for you.

Okay, so open a terminal, and first off we’ll get a sequel dump of all your current databases from XAMPP:

cd /Applications/XAMPP/xamppfiles/bin
./mysqldump -u root -p --all-databases > /Users/delboy1978uk/Desktop/all_dbs.sql

You can now import that to your new MySQL server. It’s nice to be able to call mysql from any folder, so we’ll symlink it:

sudo ln -s /usr/local/mysql/mysql /usr/bin/mysql

You can now run mysql like so:

mysql -u root

Sudo nano /etc/php.ini, PDO is enabled by default on mac, but we need to set where the MySQL socket is:

pdo_mysql.default_socket=/tmp/mysql.sock

Restart Apache, and we’re good to go!

sudo apachectl restart

No sooner did I say that I was happy with XAMPP, when suddenly it was useless and no good to me. Yes it was nice and easy to install, but heres the catch – all that goodness turns rotten when you want to upgrade a part of it.

If you’ve been reading along then you’ll know that I was in the process of preparing to install Doctrine, however, it wants at the very least, PHP 5.2, and lo and behold, along came sod and his law. XAMPP runs 5.1!

I tried swapping out the libphp5.so file with the one from the Mac’s built in Apache (5.3.10) to no avail, although someone on the internet claimed it was possible.

This left me with the choice. What now? Mamp? Zend Server Community Edition? Built in Mac Apache? The correct choice of course is the shipped with Mac Apache, as the other two are once again complete PHP stack solutions, like XAMPP, and we don’t want caught out like that again! Time to get serious and install and configure all of our server components ourselves.

It’s actually remarkably easy to move your Apache and PHP across from XAMPP. I’m guessing your htdocs are kept in the Mac’s ‘Site’ folder, like they should be. If not go into your xampp htdocs and move them across.

Next you copy your virtual host entries and put them in /etc/apache2/extra/http-vhosts.conf

Then we edit /etc/apache2/httpd.conf, uncommenting the php library module by deleting the # at the start of the line:

#LoadModule php5_module libexec/apache2/libphp5.so
to
LoadModule php5_module libexec/apache2/libphp5.so

In the <Directory “/Library/WebServer/Documents”>, we enable the use of .htaccess by having:

AllowOverride All

A little gotcha which had me stumped was that the .htaccess files in my sites still weren’t being used. It turns out you have a specific file for that:

sudo nano /private/etc/apache2/users/delboy1978uk.conf
<Directory "/Users/delboy1978uk/Sites/">
 Options Indexes MultiViews
 Options +Indexes +FollowSymLinks +ExecCGI
 AllowOverride All
 Order allow,deny
 Allow from all
</Directory>

And thats Apache sorted! We can start, stop, and restart Apache with the following commands (You can also tick a button in Apple > Preferences > Sharing > Web Sharing):

apachectl start
apachectl restart
apachectl stop

Having done that if you phpinfo(), you’ll see that there is no php.ini file! (which freaked me out a little), so I had to make one.

cd /etc
ls

There I discovered that we have php.ini.default, so I made a copy and then edited it:

cp php.ini.default php.ini
nano php.ini

In there I set the following:

error_reporting  =  E_ALL | E_STRICT
display_errors = On
html_errors = On
include_path = ".:/usr/lib/php:/usr/lib/php/Zend:/usr/lib/php/ZendX

Lastly need the zend libraries in their new home:

sudo cp -R /Application/XAMPP/xamppfiles/library/Zend /usr/lib/php/Zend
sudo cp -R /Application/XAMPP/xamppfiles/library/ZendX /usr/lib/php/ZendX

Part 2 and we’ll kill XAMPP once and for all, leaving us with a system which will be far more powerful and customisable, and then maybe I can get on with what I was trying to do, i.e.. program!

I’m preparing to install Doctrine in order to take care of Object Relational Management within my Zend Framework projects. I use XAMPP from Apache Friends, it’s nice and simple to get up and running on pretty much every platform.

If like me you use linux quite a lot, you’ll be used to some of the commands at your disposal. OS X comes with a number of these, but it annoys me when ones I frequently use are missing. One such command is wget. Now I know we can use curl -O to the same effect, so first up I edited ~/.bash_profile and added:

alias wget='curl -O'

Now when I type wget, it will run curl, so that’s one less pain in the ass. Anyway, I’m digressing.

wget http://pear.php.net/go-pear.phar

The next thing is, Mac comes with a php installed. if you type which php, it points to /usr/bin/php. We’re going to rename it, and soft link the xampp binary instead:

mv /usr/bin/php /usr/bin/php_orig
ln -s /Application/XAMPP/xamppfiles/bin/php /usr/bin/php

A quick

php --info

should tell you from pathnames etc that you are now running from your XAMPP binary. Now we can use that php command and say:

php -d detect_unicode=0 go-pear.phar

Last thing we do is create a soft link to your /usr/bin folder

ln -s /Applications/XAMPP/xamppfiles/bin/pear /usr/bin/pear

And thats us! we are now running the XAMPP php from the command line and pear is installed and configured ready to rock! Typing in pear should show you a bunch of options!

Tune in for more! Next Stop – Doctrine!

We’re playing around with a Zend Form Element Captcha Image and we need to keep the images generated somewhere. In the public folder? I’d rather not. The same applies for user uploads, and session files. However our browsers won’t be able to map an image from the url if its in the non public folders. So I’m setting up a Download Controller.

Ok so we need folders for all this stuff. In the shell at the root of the site:

mkdir uploads
mkdir session
mkdir captcha
chmod 777 uploads
chmod 777 session
chmod 777 captcha 
cd library
mkdir fonts
chmod 777 fonts

Next thing – let’s not hard code any paths. We create an ini file called
/application/configs/paths.ini
and type this out:

[paths]
uploads = /../uploads/
captcha = /../captcha/
fonts = /../library/fonts/
captchafont = Tahoma.ttf

And of course copy and paste the Tahoma.ttf file into /library/fonts.

If you haven’t created your own library, you should do it. Certain components you write will be useful in lots of sites. In this example, a standard contact form can be reused over and over again.
Create a folder in the library. Your classes will start in the Zend way; Zend_Form, Zend_Date, so choose your folder name carefully 😉 For my own nostalgic reasons of programming Atari ST’s when I was younger, my library is called TTB.
In your application.ini, add the following line:

autoloaderNamespaces[] = "TTB_"

replacing TTB with your folder name. Then put a forms folder in that and create a Contact.php

In the init section of the form (TTB_Form_Contact), we want to get the paths for the fonts for the captcha, so we create a $config variable:

//get the relevant path configuration
 $config = new Zend_Config_Ini( APPLICATION_PATH.'/configs/paths.ini', array('paths'));

And the captcha element looks like this:

$captcha = new Zend_Form_Element_Captcha('captcha', array(
    'captcha' => array(
        'captcha' => 'Image',
        'wordLen' => 6,
        'timeout' => 300,
        'width'   => 300,
        'height'  => 100,
        'imgUrl'  => '/captcha',
        'imgDir'  => APPLICATION_PATH . $config->captcha,
        'font'    => APPLICATION_PATH .$config->fonts.$config->captchafont
        )
    ));

our standard captcha URL is /captcha, so we need to set up a route. In your initRoutes in the bootstrap:

//route for download
$router->addRoute('download', new Zend_Controller_Router_Route('download/:file', array('controller' => 'download', 'action' => 'index')));
//route for captchas
$router->addRoute('captcha', new Zend_Controller_Router_Route('captcha/:file', array('controller' => 'download', 'action' => 'captcha')));

This sets up URL’s like /download/photo.jpg, or /captcha/jgf235jf4fuiy2gfc.png. They point to a download controller, so lets create one:

class DownloadController extends Zend_Controller_Action
{
    /** @var string $path the relevant folder */
    protected $_path;
    public function init()
    {
        //get the relevant path
         $this->config = new Zend_Config_Ini( APPLICATION_PATH.'/configs/paths.ini', array('paths'));
    }
    public function indexAction()
    {
        $this->_path = $this->config->uploads;
        $this->generate();
    }
    public function captchaAction()
    {
        $this->_path = $this->config->captcha;
        $this->generate();
    }
}

This sets the path to be used before rendering the image, which happens in $this->generate(), the meat and bones of the download controller:

private function generate()
{
    $file = $this->getRequest()->getParam('file');

    // disable view and layout 
    Zend_Layout::getMvcInstance()->disableLayout(); 
    $this->_helper->viewRenderer->setNoRender(); 

    // setup realpath to image 
    $path_to_image = APPLICATION_PATH.$this->_path.$file;  

    //set mimetype (content-type image/jpeg etc)
    $mtype = '';

    // magic_mime module installed?
    if (function_exists('mime_content_type')) 
    {
         $mtype = mime_content_type($path_to_image);
    }
    // fileinfo module installed?
    else if (function_exists('finfo_file')) 
    {
        $finfo = finfo_open(FILEINFO_MIME); // return mime type
        $mtype = finfo_file($finfo, $path_to_image);
        finfo_close($finfo); 
    } 
    // set headers 
    header("Content-Type: ".$mtype);

    // Open the file for reading
    $fh = fopen($path_to_image, 'r'); 

    // And pass it through to the browser
    fpassthru($fh);
}

Now you have an awesome captcha, a great way of configuring your paths, and a download controller which can serve up images from the protected areas of your site!

Ever made a new controller and action and view, just to put some static content in the view?
Well lets sort it out and create a static controller which will route to any number of the view files in the controller:

zf create controller static index-action-included[=1] default

That puts it in our module’s controller. Open it up and delete the index action, then delete the index.phtml from the views folder.

Our new Action won’t have a set view file, instead it gets the path for it’s view file from the url, and will try to find a corresponding .phtml file.

<?php
class StaticController extends Zend_Controller_Action
{
   public function init()
   {
        /* Initialize action controller here */
   }

 public function displayAction()
 {
    //get the file name from the url
    $page = $this->getRequest()->getParam('page'); 

    //load the file in the view folder
    $file = $this->view->getScriptPath(null).'/'.$this->getRequest()->getControllerName().'/'.$page.'.'.$this->viewSuffix;

    //does the view file exist?
    if (file_exists($file)) 
    {
        //render the view
        $this->render($page);
        } 
        else 
        {
            //go to our error controller
            throw new Zend_Controller_Action_Exception('Page not found', 404); 
        }
    } 
}

Now create about.phtml in application/modules/default/views/scripts/static and enter some text.
Test it by going to http://site/static/display/page/about/

Now we can add other static .phtml files in the static folder like http://site/static/display/page/contact/, or http://site/static/display/page/privacy-policy/

However the url isn’t particularly great so we can use Zend Router in the bootstrap.

We’ll create  a function in the bootstrap. The modules bootstrap! It won’t run unless it’s a function called _initThis or _initThat, so I called mine _initRoutes.
And instead of extending Zend_Application_Bootstrap_Boostrap, we make it  Zend_Application_Module_Boostrap.
Also, it’ll flake out if there are two classes called Bootstrap, so even though the namespace for the default module isn’t required, we call the class Default_Bootstrap.
We tell the router to route any url starting with /content/somepage to go to the static controller and display action:

class Default_Bootstrap extends Zend_Application_Module_Bootstrap
{
    protected function _initRoutes()
    {
        $router = Zend_Controller_Front::getInstance()->getRouter();

        //route for static content
        $router->addRoute(
        'content', new Zend_Controller_Router_Route('content/:page', array('controller' => 'static', 'action' => 'display'))
        );
    }
}

now browse to http://site/content/about, and you’ll see your static page. Awesome!

Also, since setting the project up as a modular application, we can safely delete the models, views, and controllers from the application folder, tidying things up even more.

It’s a bit fidgety setting up Zend Framework for use in a modular application, but the Zend Tool takes away a lot of the pain and misery!

zf create project whatever
cd whatever
zf create module default
zf create module other
zf enable layout

now edit your index.php in the public folder and change from production to development mode:

// Define application environment
defined('APPLICATION_ENV')
    || define('APPLICATION_ENV', (getenv('APPLICATION_ENV') ? getenv('APPLICATION_ENV') : 'development'));

The order of the application.ini settings appear to be of great importance. This worked for me:

resources.frontController.controllerDirectory = APPLICATION_PATH "/controllers" 
resources.frontController.moduleDirectory = APPLICATION_PATH "/modules" 
resources.layout.layoutPath = APPLICATION_PATH "/layouts/scripts/"
resources.modules[] =

It won’t find the error controller and we need our default index controller:

zf create controller index index-action-included[=1] default
zf create controller error index-action-included[=1] default

The default module doesn’t require any namespace, so class Default_IndexController should be changed to just Index_Controller,
and the same goes for the Default_ErrorController.

Copy and paste the error() method from the original error controller in application/controllers, and paste it in to /application/modules/default’s error controller. Do the same for the view file.

Make a slight edit to the new error controller’s view file.

<h1>An error occurred!</h1>

The exclamation will help us know if the modules error controller is being used or not.

Replace the content of the default modules index view with some text (Hello Modular World?) to distinguish it apart from the original index controller. Do the same (Hello different module)  for the index viewof the ‘other’ module.

Now browse to your site, and hopefully you won’t be seeing the Welcome to Zend Framework message of the original index controller’s view file, and instead see your hello world message. add /other on to the end of your url, and try that. Your other message should appear. Finally mess with your url and try to go to /this/will/never/work. You should see the error message with the exclamation.

Finally lets get the layout stuff happening. go in to /application/layouts/scripts/layout.phtml and add something:

<h1>Awesome!</h1>
<?php echo $this->layout()->content; ?>

And that’s us good to go! Using modules in Zend Framework is a great way of creating great reusable code, and by nature helps keep your code nice n loosely coupled.