CSS2LESS – PHP class

If you are a PHP developer who also works in frontend stuff you should learn about LESS (Leaner CSS) which is a CSS pre-processor and it allows you to make CSS more maintainable.

I’ve found a cool PHP class which can convert CSS into programmable CSS with LESS syntax. It can parse a given CSS style sheet and extract certain common property constant values to turn them into variables in the converted output using LESS.

Currently it turns the CSS properties into LESS variables: color, width, height, font-family and font-size.

You can find this class here.

I was playing with it and it works like a charm! 😀

Doctrine: How to define relationships

In this post we will review how to define Doctrine relationships, from one-to-one to many-to-many relationships.

One-to-One

To explain this relationship we do it with an example. We suppose that we have two entities (User and Email); when we define the Email entity we should add a ‘user_id‘ property (which is the foreign key) due to the User entity is the “owner” of the relationship, this means the User has an Email. We always need to identify the “owner” side and add the foreign key to the entity which belongs to the “owner” entity. When we use this relationship, Doctrine uses a hasOne method. Let’s see how to define it with yaml:

1
2
3
4
5
6
7
8
9
Email:
  columns:
    user_id: integer
    address: string(150)
  relations:
    User:
      local: user_id
      foreign: id
      foreignType: one

One-to-Many and Many-to-One

Now, let’s suppose we have the same User entity which can have many phone numbers (for that we have a Phonenumber entity). We should follow the same convention than in the one-to-one relationship and define the foreign key in the Phonenumber entity, which belongs to the User entity. When we define this kind of relationship Doctrine uses the hasOne method for the Phonenumber entity and the hasMany method for the User entity. Let’s see how to define it with yaml:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
User:
  // Some properties definitions here
  relations:
    Phonenumbers:
      type: many
      class: Phonenumber
      local: id
      foreign: user_id

Phonenumber:
  columns:
    user_id: integer
    phonenumber: string(50)
  relations:
    User:
      local: user_id
      foreign: id

Many-to-Many

And last but not least, when we need to define a many-to-many we have the need to add an extra table :-S, called JOIN table. Following with our User entity, let’s suppose we have a new entity called Group, and we know that a User can belong to a many Groups and that a Group can have a lot of Users. In this case, if we remove an User we should not remove the Group, but yes the relationship. When we define this kind of relationship Doctrine uses the hasMany method in both entities. Let’s see how to define it with yaml:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
User:
  // Some properties definition here
  relations:
    Groups:
      class: Group
      local: user_id
      foreign: group_id
      refClass: UserGroup

Group:
  tableName: groups
  columns:
    name: string(30)
  relations:
    Users:
      class: User
      local: group_id
      foreign: user_id
      refClass: UserGroup

UserGroup:
  columns:
    user_id:
      type: integer
      primary: true
    group_id:
      type: integer
      primary: true

Well, I hope this post will be helpful to understand and know how to define Doctrine relationships.

Ref: Doctrine documentation

 

Symfony and Doctrine behaviors

This post is about symfony and doctrine behaviors which are useful for daily uses.

These behaviors allow us to speed up the application development and in this post we will find short descriptions about most common behaviors.

Basically, a behavior will give us some relationships, algorithms and other features between our business entities. Those behaviors are deeply configurable (they should be at least), that configurations include: activate/deactivate behavior features, rename some additional schema attributes, etc.
We can use many Doctrine’s behaviors in our projects, such as core behaviors, extension behaviors, symfony’s plugins, or well, we can build our own behaviors.

Core Behaviors

Doctrine already comes with many behaviors (core behaviors), those are:

  • # Versionable – adds a new table to store our diferent versions of the entity to keep our entities versionable.
  • # Timestampable – this probably is the most popular behavior, adds two new columns (created_at and updated_at) to automatically store the dates when the entity is created or updated respectively.
  • # Sluggable – adds a new column (slug) which is unique and could be use by sfDoctrineRoute to refer the entity.
  • # I18n – adds a new table to provide Internationalization (I18n) to our model, this behavior is esential when we develop multi-language apps.
  • # NestedSet – adds a few columns (root_id, lft, rgt and level) to our entity to develop a hierarchy data structure (tree structure).
  • # Searchable – choses the columns of our entity which we want to index and adds a new table, speeding up the search engine development.
  • # Geographical – adds the longitude and latitude columns storing specific geographical coordinates, and provides us a getDistance() method to calculate the distance between 2 geographical entities.
  • # SoftDelete – adds a new deleted_at column which defines if a record has been marked as deleted (and when). It is an useful behavior when we need important consistency data.

Extension Behaviors

Also, we can use the Doctrine exntesions:

  • # Blameable – adds an additional level to audit our entities, it allows us to follow who has created or updated an entity.
  • # EventLoggable – saves a log of every Doctrine’s event (pre/post Delete/Insert/…) used by a record.
  • # Localizable – gives us the functionality to convert measure units (for instance, kilometers to miles).
  • # Locatable – gives us the functionality to use Google Maps to automatically fill our entity with longitude and latitude information from Google.
  • # Sortable – gives us the functionality to sort our entities.
  • # Taggable – adds abilities to tagging, it creates two tables using m:n relationships and provides easy tags administration.

Plugin Behaviors

Finally, there are some symfony’s plugins which gives us more behaviors:

I hope this post is useful.

PhpMyAdmin: Keeping the session alive

Here we will see how to configure PhpMyAdmin to avoid the “login again” request when the session expires.

If the “login again” message is bothering you because the session has expired after 30 minutes (1800 seconds), which is a really short time :-), we can follow the next steps to keep the session alive.

The first step is to edit the configuration file (config.inc.php):

1
user@unix:~$ gedit /path/to/your/phpmyadmin/config.inc.php

And replace the below line:

1
$cfg['Servers'][$i]['auth_type'] = 'cookie';

For this:

1
$cfg['Servers'][$i]['auth_type'] = 'http';

And, at the end of the file we should add:

1
$cfg['LoginCookieValidity'] = 86400;

That’s it, we should save the modifications and enter PhpMyAdmin again.

PHP: Implementing MVC design pattern

Based in the symfony docs we will try to summarize the implementation of MVC with PHP.

In a previous post we explained the MVC design pattern, and now we’re going to see how to implement it in PHP.

To implement this pattern and try to understand it a little more we’ll see how to transform a basic PHP application in a MVC app. In this case, we’ll build a posts list in a blog. To show a post list from the database in the PHP spaghetti way the script would looks like:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
<?php
// Connecting, selecting database
$link = mysql_connect('localhost', 'myuser', 'mypassword');
mysql_select_db('blog_db', $link);
 
// Performing SQL query
$result = mysql_query('SELECT date, title FROM post', $link);
?>

<html>
    <head>
        <title>List of Posts</title>
    </head>
    <body>
        <h1>List of Posts</h1>
        <table>
        <tr><th>Date</th><th>Title</th></tr>
<?php
// Printing results in HTML
while ($row = mysql_fetch_array($result, MYSQL_ASSOC)) {
    echo "<tr>";
    printf("<td> %s </td>", $row['date']);
    printf("<td> %s </td>", $row['title']);
    echo "";
}
?>

        </table>
    </body>
</html>
<?php
// Closing connection
mysql_close($link);
?>

The above script is easy to write, fast to execute, but hard to maintain; some of the trouble we can find is the absence of errors checking (what happen if the db connection fails?), the HTML and the PHP code are all mixed and the script is tied to the MySQL database.

Splitting the presentation out

The echo and printf calls make the code hard to read. To edit the HTML is a pain in the above script, so lets split the code in two sides. First, the PHP code with all the business logic in a Controller (index.php):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<?php
// Connecting, selecting database
$link = mysql_connect('localhost', 'myuser', 'mypassword');
mysql_select_db('blog_db', $link);
 
// Performing SQL query
$result = mysql_query('SELECT date, title FROM post', $link);
 
// Filling up the array for the view
$posts = array();
while ($row = mysql_fetch_array($result, MYSQL_ASSOC)) {
    $posts[] = $row;
}
 
// Closing connection
mysql_close($link);
 
// Requiring the view
require('view.php');

And, the View script (view.php):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<html>
    <head>
        <title>List of Posts</title>
    </head>
    <body>
        <h1>List of Posts</h1>
        <table>
            <tr><th>Date</th><th>Title</th></tr>
<?php
foreach ($posts as $post):
?>
            <tr>
                <td>
                    <?php echo $post['date']; ?>
                </td>
                <td>
                    <?php echo $post['title']; ?>
                </td>
            </tr>
<?php
endforeach;
?>

        </table>
    </body>

To determine if the view is clean enough, a good rule is to have the minimum amount of PHP code in a way that the view could be understand it by a designer without PHP knowledge. The most common and proper PHP syntax in the view are echo, if/endif and foreach/endforeach. Also, there should not be PHP code printing HTML tags.

Hence, all the logic is moved into the controller (containing only PHP, with no HTML)
Por ende, toda la lógica es movida al controlador, y contiene solo código PHP, sin HTML. Como algo importante, deberías imaginar que el mismo controlador debería poder ser usado para diferentes presentaciones (vistas), tales como paginas HTML, archivos PDF, o en una estructura XML.

Isolating the data manipulation

Most of the controller code is dedicated to the data manipulation. But, what happen if we need to list the post for another controller, for instance, one which has a feed RSS output, or if we want to change the data model, like change the table name from post to weblog_post, or we have to change the database engine from MySQL to PostgreSQL. To be able to do all those things we have to remove the data manipulation from the controller and put that logic in the model (model.php):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<?php
function getAllPosts()
{
    // Connecting, selecting database
    $link = mysql_connect('localhost', 'myuser', 'mypassword');
    mysql_select_db('blog_db', $link);
 
    // Performing SQL query
    $result = mysql_query('SELECT date, title FROM post', $link);
 
    // Filling up the array
    $posts = array();
    while ($row = mysql_fetch_array($result, MYSQL_ASSOC)) {
        $posts[] = $row;
    }
 
    // Closing connection
    mysql_close($link);
 
    return $posts;
}

And modifying the controller (index.php) to include the model:

1
2
3
4
5
6
7
8
9
<?php
// Requiring the model
require_once('model.php');
 
// Retrieving the list of posts
$posts = getAllPosts();
 
// Requiring the view
require('view.php');

In this way we have a really readable controller since if unique task is to get the data from the model and pass it to the view. In more complex apps, the controller also handles the request, the user session, the authentication and much more functionalities.

Source: Symfony documentation

PHP 5.3.3. released

The PHP 5.3.3 was released a few days ago.

The PHP core team has announced the 5.3.3 availability. This release has focused on improve security and stability issues with more than 100 fixed bugs, most of them related to security issues.

Previous versions incompatibility
For previous version than 5.3.3 there is a big incompatibility. The methods with the same name as the class name used by the namespace are not anymore considered as the class constructor. This change does not affect the classes those do not use namespaces.

1
2
3
4
5
6
7
8
9
10
<?php
namespace Foo;
class Bar
{
    public function Bar()
    {
        // Act as constructor in PHP 5.3.0-5.3.2
        // Act as a regular method in PHP 5.3.3
    }
}

This change does not have impact in migrations from PHP 5.2.x, due to namespaces were introduced from PHP 5.3.0.

PHP for Android

A few days ago was released a project to build applications based on Android with PHP.

This project allows us to build apps for Google’s operating system with the most popular scripting language (PHP). With this project the PHP developers will be able to run PHP in every device based on Android.

The phpforandroid.net project was build over the Android Scripting Environemnt (ASE) which was renamed to Scripting Layer for Android (SL4A), which allows developers to run scripting languages like PHP and Phyton.

The project is at its beginning and for sure it will evolve with the time and the community’s help. I was playing a little bit and it works perfectly so far.

The project also has a really good documentation and we can use an Android emulator to test out apps.

Here there is a video that shows how phpforandroid works:

Symfony: generate-admin filters customization

In this post we will see how to customize the generate-admin filters to get more customized filters adapted to our needs.

If some time we used the Symfony generate-admin we could see that we have the ability to filter what data to show. These filters allow us to filter by whatever existing field in the entity. Now, we will see how to add a customized field to the filters, so we can filter according to our needs.

Let’s suppose we have an User and Phonenumber objects and in the phonenumbers list we want to filter by user. To do that we can modify the generator.yml file in the phonenumber module. In phonenumber/config/generator.yml:

1
2
3
config:
  filter:
    display: [ another, field, user_by_name]

Also, we need to define the widget and validator to this new field in lib/filter/doctrine/PhonenumberFormFilter.class.php:

1
2
3
4
5
6
7
8
9
<?php
public function configure()
{
    //...
    $this->setWidget('user_by_name', new sfWidgetFormFilterInput(array('with_empty' => false));
 
    //...
    $this->setValidator('user_by_name', new sfValidatorPass(array('required' => false));
}

In the same form class we need to overwrite the getFields() method with the new added field:

1
2
3
4
5
6
7
8
<?php
public function getFields()
{
    $fields = parent::getFields();
    $fields['user_by_name'] = 'custom';
   
    return $fields;
}

And last, we need to add the method which does the filtering, this field follows the convention addColumnNameColumnCriteria:

1
2
3
4
5
6
7
8
9
10
11
12
<?php
public function addUserByNameColumnQuery($query, $field, $value)
{
    $text = $value['text'];
    if ($text) {
        $query->leftJoin($query->getRootAlias().'.User u')->andWhere('(u.first_name LIKE ?
            OR u.last_name LIKE ?
            OR u.username LIKE ?)'
, array("%$text%", "%$text%", "%$text%"));
    }
   
    return $query;
}

Done. We have a customized filter.

Symfony: conditional validator

Here we will see how to implement a conditional validator for Symfony’s forms.

As you may know the form framework inside Symfony gives us the ability to use validators for each form field, therefore we can validate the required fields, the data format, etc.

When we need to validate certain logic for a field which could not be accomplish it with the normal Symfony validators, we have to use a post validator. A post validator is executed after all normal Symfony validators and it receives an array with all entered values through the form.

As a practical case, we might want to validate that an entered password in a login form is equal to the entered username. Obviously, this is a easy but practical example.

The login form could be as follow:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
<?php
class loginForm extends sfForm
{
    public function configure()
    {
        $this->setWidgets(array(
            'username'  => new sfWidgetFormInput(),
            'password'  => new sfWidgetFormInputPassword(),
        ));
 
        $this->setValidators(array(
            'username' => new sfValidatorString(array('required' => true)),
            'password' => new sfValidatorString(array('required' => true)),
        ));
 
        $this->widgetSchema->setNameFormat('login[%s]');
 
        // add a post validator
        $this->validatorSchema->setPostValidator(
            new sfValidatorCallback(array('callback' => array($this, 'checkPassword')))
        );
    }
 
    public function checkPassword($validator, $values)
    {
        // before validating the password, check that the username is not empty
        if (!empty($values['username']) && $values['password'] != $values['username']) {
            // password is not correct, throw an error
            throw new sfValidatorError($validator, 'Invalid password');
        }
 
        // password is correct, return the clean values
        return $values;
    }
}

In this way, the validator callback will throw a “global” error when the entered password is not equal to the entered username. If we want to get a specific field error we should modify the checkPassword() method:

1
2
3
4
5
6
7
8
9
10
11
12
13
<?php
public function checkPassword($validator, $values)
{
    if (!empty($values['username']) && $values['password'] != $values['username']) {

        $error = new sfValidatorError($validator, 'Invalid password');
 
        // throw an error bound to the password field
        throw new sfValidatorErrorSchema($validator, array('password' => $error));
    }
 
    return $values;
}

That is! I hope it’s helpful.