Skip to content

When there is a method to get an object, always use it!

2012 May 16
by Richard Knop

I have just learned an important lesson. When using a framework (doesn’t matter if it’s Zend Framework, Symfony or anything else), always use a getter method of the controller object if available. There usually is a reason for why it exists. Simple example.

I was writing some controller unit tests in Zend Framework extending Zend_Test_PHPUnit_ControllerTestCase. Inside my controller I was creating a new instance of a request object like this:

  1. $request = new Zend_Controller_Request_Http;

Instead of using the getter method:

  1. $request = $this->getRequest();

The unit tests were failing and I did not understand why. The issue was that I was using an authentication controller plugin which checked for an authentication header and redirected request to a different controller action when the request did not have the correct header.

Of course, I had 100% coverage of the authentication plugin so I was sure the problem was inside the controller. It was simple – by creating a new instance of the request class, I was dropping any headers from the request. Therefor, all my controller tests were being redirected to a different action by the plugin, even the tests that were supposed to simulate a correctly authenticated request.

Using the getter method to get the request object solved the mysterious issue.

Removing all attributes from DOMNode in a foreach loop is not a good idea

2012 May 16
tags:
by Richard Knop

So few days ago in work I needed to remove all attributes from a DOMNode instance while parsing an XML response from a web service. Naively, I wrote a code like this:

  1. foreach ($element->attributes as $attribute) {
  2.     $element->removeAttribute($attribute->name);
  3. }

It turns out that the attributes collection is reindex each time you remove an attribute. So the code above would delete only the first attribute in a case the node had 2 attributes, it would only remove first two attributes if the node had 4 attributes and so on.

The correct way to do this:

  1. while ($element->attributes->length) {
  2.     $element->removeAttribute($element->attributes->item(0)->name);
  3. }

Passing array of objects by reference is faster in PHP

2012 March 3
tags:
by Richard Knop

I have decided to make a simple benchmark in order to prove what I have suspected for a long time – when you pass an array of objects by reference, it is faster than passing it by value.

When you pass an array of objects without reference, PHP will have to create a new copy of the array which can be quite resources consuming, especially with arrays containing large objects. Here is my benchmark:

  1. <?php
  2.  
  3. class Foo
  4. {
  5.     private $bar;
  6.  
  7.     public function __construct($bar)
  8.     {
  9.         $this->bar = $bar;
  10.     }
  11.  
  12.     public function getBar()
  13.     {
  14.         return $this->bar;
  15.     }
  16.  
  17.     public function setBar($bar)
  18.     {
  19.         $this->bar = $bar;
  20.     }
  21.  
  22.     public static function reverseBars(array $foos)
  23.     {
  24.         foreach ($foos as $foo) {
  25.             $foo->setBar(strrev($foo->getBar()));
  26.         }
  27.         return $foos;
  28.     }
  29.  
  30.     public static function reverseBarsByReference(array &$foos)
  31.     {
  32.         foreach ($foos as $foo) {
  33.             $foo->setBar(strrev($foo->getBar()));
  34.         }
  35.     }
  36. }
  37.  
  38. function test1()
  39. {
  40.     $foos = array();
  41.     for ($i = 0; $i < 10; ++$i) {
  42.         $foos[] = new Foo('foo'.$i);
  43.     }
  44.  
  45.     $start = microtime(true);
  46.  
  47.     $foos = Foo::reverseBars($foos);
  48.  
  49.     $end = microtime(true);
  50.  
  51.     return $end-$start;
  52. }
  53.  
  54. function test2()
  55. {
  56.     $foos = array();
  57.     for ($i = 0; $i < 10; ++$i) {
  58.         $foos[] = new Foo('foo'.$i);
  59.     }
  60.  
  61.     $start = microtime(true);
  62.  
  63.     Foo::reverseBarsByReference($foos);
  64.  
  65.     $end = microtime(true);
  66.  
  67.     return $end-$start;
  68. }
  69.  
  70. $n = 50000;
  71.  
  72. $times1 = array();
  73. for ($i = 0; $i < $n; ++$i) {
  74.     $times1[] = test1();
  75. }
  76.  
  77. $times2 = array();
  78. for ($i = 0; $i < $n; ++$i) {
  79.     $times2[] = test2();
  80. }
  81.  
  82. $withoutReference = array_sum($times1)/$n;
  83. $withReference = array_sum($times2)/$n;
  84. echo 'Without reference: ', $withoutReference, '
  85. ';
  86. echo 'With reference: ', $withReference, '
  87. ';
  88. $onePercent = $withoutReference/100;
  89. $percentFaster = 100 - $withReference/$onePercent;
  90. echo 'Without reference is ', $percentFaster, '% faster :) ';

And the results:

So it appears on average, passing arrays of objects by reference is 10% faster. What do yo think? Any objections to my benchmark?

A MySQL procedure to drop all tables in a specific database

2012 February 4
by Richard Knop

Here is a nice MySQL stored procedure which can be used to delete all tables in a specified database. It takes one argument – a database name – and it deletes all tables in that database. Be careful when using this procedure :)

DROP PROCEDURE IF EXISTS drop_all_tables_from_specified_database;

DELIMITER $$
CREATE PROCEDURE drop_all_tables_from_specified_database(IN dbname CHAR(50))
BEGIN
    DECLARE done INT DEFAULT FALSE;
    DECLARE tblname CHAR(50);
    DECLARE cur1 CURSOR FOR SELECT table_name FROM information_schema.tables WHERE table_schema = dbname COLLATE utf8_general_ci;
    DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;

    SET foreign_key_checks = 0;

    OPEN cur1;
    read_loop: LOOP
        FETCH cur1 INTO tblname;
        IF done THEN
            LEAVE read_loop;
        END IF;
        SET @database_name = dbname;
        SET @table_name = tblname;
        SET @sql_text = CONCAT('DROP TABLE ', @database_name, '.' , @table_name, ';');
        PREPARE stmt FROM @sql_text;
        EXECUTE stmt;
        DEALLOCATE PREPARE stmt;
    END LOOP;
    CLOSE cur1;

    SET foreign_key_checks = 1;

END$$
DELIMITER ;

CALL drop_all_tables_from_specified_database('test');

DROP PROCEDURE drop_all_tables_from_specified_database;

Install PHPUnit on FreeBSD 8.2

2012 February 4
by Richard Knop

Here is how to install PHPUnit on FreeBSD 8.2 so you can write unit tests for your code:

#portsnap fetch
#portsnap extract
#portsnap update
#cd /usr/ports/devel/pear
#make
#make install

#pear channel-discover pear.symfony-project.com
#pear install symfony/YAML

#pear channel-discover pear.phpunit.de
#pear install phpunit/PHPUnit

#pear config-get php_dir

The last line will show you the directory where PHPUnit was installed. Add it to your include path and you are ready to go:

  1. set_include_path('/usr/local/share/pear');
  2. require_once('PHPUnit/Autoload.php');
  3.  
  4. class FooTest extends PHPUnit_Framework_TestCase
  5. {
  6. }

MAMP 2.0.5 PHP PEAR not working

2012 February 4
by Richard Knop

After installing MAMP 2.0.5 on my Macbook I have found out PEAR doesn’t work (I wanted to use it to install PHPUnit for unit testing). This solves the problem:

#rm /Applications/MAMP/bin/php/php5.3.6/conf/pear.conf

Once you delete that file PEAR will start working so you can install PHPUnit.

Django missing admin CSS stylesheets

2012 January 22
tags:
by Richard Knop

Follow up on three of my previous posts:

I have been following the official Django tutorial and creating the polls app. I have decided to test my app in a FreeBSD virtual machine with properly configured Apache instead of the development server though.

I got to the part where I am supposed to log in into the automatically generated admin area.  The http://IP_OF_MY_TEST_VM/admin/ works and I get the admin sign in page but the links to stylesheets are not working. It’s simple to fix that.

My app is located in /usr/local/www/myapp folder and it’s document root is set via httpd.conf to /usr/local/www/myapp/public directory. So:

#cd /usr/local/www/myapp/public
#mkdir static
#cd static
#mkdir admin
#cp -r /usr/local/lib/python2.7/site-packages/django/contrib/admin/media/* /usr/local/www/myapp/public/static/admin

That should copy free directories (css, img, js) into your document root. One more thing, edit your virtual host configuration to tell mod_wsgi to match /static/ to /usr/local/www/myapp/public/static/:

WSGIPythonPath /usr/local/www
<VirtualHost *:80>
  ServerName localhost.home
  ServerAlias localhost.home

  DocumentRoot /usr/local/www/myapp/public
  Alias /static/ /usr/local/www/myapp/public/static/

  <Directory /usr/local/www/myapp/public>
  Order allow,deny
  Allow from all
  </Directory>

  WSGIScriptAlias / /usr/local/www/myapp/wsgi.py

  <Directory /usr/local/www>
  Order allow,deny
  Allow from all
  </Directory>
</VirtualHost>

Restart Apache:

#/usr/local/sbin/apachectl restart

And go to http://IP_OF_MY_TEST_VM/admin/. CSS stylesheets should now get loaded properly :)

PostgreSQL chear sheet

2012 January 22
tags: ,
by Richard Knop

Since I have been using MySQL for a long time, transition to PostgreSQL is a little bit difficult. I will be posting some useful commands here for my own reference. This post will be getting updated a lot.

I have explained how to install PostgreSQL on FreeBSD 8.2 in my previous post.

To create a database:

#su pgsql
$ createdb db_name
$ exit

To drop a database:

#su pgsql
$ dropdb db_name
$ exit

To list all databases:

#psql -l

To open psql prompt for a database and a user:

#psql db_name -U user

After opening psql prompt with psql db_name -U user

To list all tables in a database:

\d

To describe  a table structure:

\d table_name

Psql help:

\?

To quit psql prompt:

\q

Install PostgreSQL on FreeBSD 8.2 and make it work with Django

2012 January 22
tags:
by Richard Knop

Follow up on my previous two blog posts:

I am going to write down installation steps for PostgreSQL on FreeBSD 8.2 so it can be used with django.db.backends.postgresql_psycopg2 adapter.

#cd /usr/ports/databases/postgresql91-server
#make
#make install

Add this line to /etc/rc.conf:

postgresql_enable="YES"

Next, initialize a PostgreSQL database cluster:

#/usr/local/etc/rc.d/postgresql initdb

Now add this line to /usr/local/pgsql/data/postgresql.conf:

listen_addresses = '*'

Thirdly, add this line to /usr/local/pgsql/data/pg_hba.conf:

host   all   all   127.0.01/32 md5

Reboot. Now let’s create a new user for our PostgreSQL database:

#su pgsql
$ createuser -sdrP username
Enter password for new role: ******
Enter it again: ******

$ exit

Finally, we need to install psycopg2 client in order to be able to connect to the PostgreSQL server from a Django web application.

#pip install psycopg2
#/usr/local/sbin/apachectl restart

Cool. Now you should be able to connect to the PostgreSQL server from your Django app. Make sure to create a database first:

#su pgsql
$ createdb myapp
$ exit

Now go to your Django application folder and edit settings.py. Use django.db.backends.postgresql_psycopg2 as ENGINE, also set NAME, USER and PASSWORD fields. Reload the Django app in the browser and it should work fine.

How to install and configure Django with mod_wsgi on FreeBSD 8.2

2012 January 21
tags:
by Richard Knop

This is a follow up on my previous post: How to install and configure mod_wsgi on FreeBSD 8.2

I will assume you have followed all steps in the previous blog post and have FreeBSD 8.2 with Apache, Python and mod_wsgi installed and configured properly. We will use the same directory as we used for the hello world python WSGI web app in the previous article. However, we will re-create it with Django so let’s delete if first:

#rm -rf /user/local/www/myapp

Let’s install Django:

#cd /usr/ports/devel/py-pip
#make
#make install

Either refresh your shell path or reboot your virtual machine and install Django via pip:

#pip install django

Test Django installation:

#python
>>>import django

Next, I used UNIX find comman to find django-admin.py file:

#find / -name django-admin.py
/usr/local/bin/django-admin.py
/usr/local/lib/python2.7/site-packages/django/bin/django-admin.py

Let’s go to the /usr/local/www directory:

#cd /usr/local/www

And type:

#/usr/local/bin/django-admin.py startproject myapp

This will create a myapp directory with couple of files inside it, basically a standard Django project.

The only thing remaning is to configure mod_wsgi. First, edit the Apache configuration file:

#ee /usr/local/etc/apache22/httpd.conf

It should look exactly like the one in my previous blog post, the only thing changed is that I have moved the virtual host into a separate file. So delete the virtual host configuration and add an Include directive:

Include /usr/local/www/myapp/httpd.conf

I am basically telling the Apache to include contents of another httpd.conf file which will be inside the /usr/local/www/myapp folder. This way the virtual host configuration for our app will be inside the app home folder which makes way more sense. So create a new httpd.conf file:

#cd /usr/local/www/myapp
#ee httpd.conf

Configure an Apache virtual  host for our Django app:

WSGIPythonPath /usr/local/www
<VirtualHost *:80>
  ServerName localhost.home
  ServerAlias localhost.home

  DocumentRoot /usr/local/www/myapp/public

  <Directory /usr/local/www/myapp/public>
  Order allow,deny
  Allow from all
  </Directory>

  WSGIScriptAlias / /usr/local/www/myapp/wsgi.py

  <Directory /usr/local/www>
  Order allow,deny
  Allow from all
  </Directory>
</VirtualHost>

Finally, you might have noticed that our Django app is missing the wsgi.py file mentioned in the httpd.conf. Let’s create it:

#ee wsgi.py

The simplest Django app will look like this:

import os
os.environ['DJANGO_SETTINGS_MODULE'] = 'myapp.settings'

import django.core.handlers.wsgi
application = django.core.handlers.wsgi.WSGIHandler()

That’s it. Open the app in your browser and you should see a page like this: