Logging with FirePHP in ZF2

9 comments

Posted on 10th October 2012 by Bart McLeod in Zend Framework |ZF 2

Yesterday I wanted to set up logging to FirePHP in CuddleFish (my pet project business framework). I thought it would be easy, and looking back, it is very easy. Before I figured out how to set it up, it was not so easy, so I’d better blog about it to remind myself of how it’s done.

First of all, you have to set up FirePHP. You can download it from the FirePHP website or install it using pear:

pear channel-discover pear.firephp.org
pear install firephp/FirePHPCore

Next, in the Module.php file of your module, you can add a service that provides the configured logger:

// at the top of the file:
use Zend\Log\Logger;
use \Zend\Log\Writer\FirePhp as FirePhpWriter;
use \Zend\Log\Writer\FirePhp\FirePhpBridge;

// Note that I place FirePHPCore in vendor
require_once 'vendor/FirePHPCore/FirePHP.class.php';

// further down
    public function getServiceConfig()
    {
        return array(
            'factories' => array(
                // [..] other factories for other serivces left out
                'log' => function($sm) {
                    $log = new Logger();
                    $writer = new FirePhpWriter(new FirePhpBridge(new \FirePHP()));
                    $log->addWriter($writer);
                    return $log;
                },
            ),
        );
    }

Simplifying it

In fact, since we require_once the core FirePHP class, there is no need to pass it to the constructor of the writer using the bridge. I only came to realize this while writing this post. When the FirePHP class exists, it will be used automatically by the writer. So the simplified code becomes:

// at the top of the file:
use Zend\Log\Logger;
use \Zend\Log\Writer\FirePhp as FirePhpWriter;

// Note that I place FirePHPCore in vendor
require_once 'vendor/FirePHPCore/FirePHP.class.php';

// further down
    public function getServiceConfig()
    {
        return array(
            'factories' => array(
                // [..] other factories for other serivces left out
                'log' => function($sm) {
                    $log = new Logger();
                    $writer = new FirePhpWriter();
                    $log->addWriter($writer);
                    return $log;
                },
            ),
        );
    }

Now if you need the log somewhere, say in a controller, you can pass it in using the factory for the controller and call:

$this->info('It works');

Alternatively you can call getServiceLocator() inside the controller to get the ServiceManager and get the log instance:

$this->getServiceLocator()->get('log')->info('Will work equally well');

There is however a downside to this: If you have a lot of calls to the log, it is more code to type than just calling $this->log->info(‘something’);

If you have an initalizer in your controller, you can set the log there:

// inside initializer
$this->log = $this->getServiceLocator()->get('log');

If you use a factory to create your controller, you can add a method setLog() to your controller:

public function setLog($log)
{
    $this->log = $log;
}

The factory can be a closure in the controller configuration, like we did for the log:

    public function getControllerConfig()
    {
        return array(
            'factories' => array(
                'index' => function($controllers) {
                    $sm = $controllers->getServiceLocator();
                    $controller = new Controller\IndexController();
                    $controller->setLog($sm->get('log'));
                    return $controller;
                },
            ),
        );
    }

Now the log is available as $this->log right after instantiation of the controller.

 

9 Comments
  1. Bart McLeod says:

    Thanks @samsonasik for telling me that commenting failed because of a permission error. SiCaptcha should detect that I think.

    10th October 2012 at 7:19 am

  2. Abdul Malik Ikhsan says:

    I think

    $this->log->info('It works');
    

    should be :

    $this->getServiceLocator()->get('log')->info('It works');
    

    10th October 2012 at 7:22 am

  3. Bart McLeod says:

    Thanks Abdul, you are right. I was assuming a situation where you have already injected the log into the controller (into $this->log). However, injecting it is an unnecessary step, since we have getServiceLocator(). I will edit the post to reflect this.

    10th October 2012 at 7:38 am

  4. Abdul Malik Ikhsan says:

    You’re welcome

    10th October 2012 at 8:05 am

  5. cake php applications says:

    Zend Framework has really neat logging component, Zend_Log. Zend_Log is decoupled into four objects: Log, Writer, Filter and Formatter. Each of object is exchangeable.

    10th October 2012 at 5:28 am

  6. gafreax says:

    Hi, really good article. But I do it in a little different way: i install firephp with composer with this simple command in my project home:

    php composer.phar require “firephp/firephp-core” : “dev-master” && php composer.phar update -o

    Best Wishes!

    10th October 2012 at 10:23 am

  7. Bart McLeod says:

    Just replying to myself here. While you can use $this->getServiceLocator() to pull any service into the controller, this is not the idea of dependency injection. It only means you now depend on a string (‘log’ in this case). Using either setter injection or constructor injection you can avoid this.

    10th October 2012 at 7:47 pm

  8. Pablo Lopes says:

    Great article.
    Help me a lot.

    Thanks

    10th October 2012 at 8:37 pm

  9. Bart McLeod says:

    I do it the same way nowadays and it works great indeed. It took me a little while to get used to Composer, but now that I’m used to it I think it’s a great tool.

    10th October 2012 at 10:09 pm

Leave a comment

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

By submitting this form, you accept the Mollom privacy policy.