isUnique validation of limited length field

Working on a project I had following problem.

I had to set isUnique validation of a field. The field has VARCHAR(10) type. When I save the data the “isUnique” validation doesn’t work as expected while I was sure that the there is such record in the database. Digging through the problem it turn out that the problem is in the length of the DB column.

Let me explain. The field was length 10, but in the form I’ve put the value which is 11 characters long, so when the first data is submitted instead of the 11 characters, only 10 are saved in the DB table. My value was 456-23-2010 while in the db it’s saved 456-23-201.

So when inserting the new data the script checks 456-23-2010 against the database where is stored 456-23-201. and of course it passes the validation. While on the edit action strangely it appear that the value it is not unique any more (because there are already 2 records 456-23-201 in the db. 🙂

A little bit tricky, because at first glance the data is almost the same. For sure if the inserted string was large than the saved in the DB I would spot it easily, but to me the number was really the same.

There are 2 possible ways where I would think how to solve this problem in the future: Either modifying the Bake template for my applications, or using better validation technique – where the value is trimmed up to length of the field.

I was wondering what would be the better way?

Share it:
  • Facebook
  • Twitter
  • Digg
  • StumbleUpon
  • del.icio.us
  • Google Bookmarks
  • Yahoo! Buzz
  • Add to favorites
  • Identi.ca

Working with nested data and find method with breadcrumbs in CakePHP

Do you working with tree data in your projects?

Well, in CakePHP there is a Tree behavior which will help you to handle such structures. Let me show you how to use it in your projects. Hierarchical data structures are very well described here by Mike Hillyer and I would suggest you to take a look before you continue reading.

Let’s say we have following data structure:

CREATE TABLE IF NOT EXISTS `categories` (
  `id` INT(10) NOT NULL AUTO_INCREMENT,
  `parent_id` INT(10) DEFAULT NULL,
  `name` VARCHAR(255) DEFAULT NULL,
  `lft` INT(10) DEFAULT NULL,
  `rght` INT(10) DEFAULT NULL,
  PRIMARY KEY  (`id`)
)

Note, that in that table there are 3 special fields: parent_id, lft and rght.

The first one is very familiar to everyone who understanding the tree structures. The other 2 are to handle the MPTT logic (see the article mentioned above). The beautiful part of using Tree behavior is that you don’t need to worry about these 2 extra columns. The behavior will fill them automatically. 🙂

So, continue with the example. Attach the Tree behavior to your Model:

<?php
class Category extends AppModel {
    var $name = 'Category';
    var $useTable = 'categories';
    var $actsAs = array('Tree' => 'nested');
}
?>

That’s it. Now when you save (insert or update) your data into the table, the fields lft and rght will be automatically populated with the correct values. Of course your task is to have proper value set in parent_id 🙂

Why this is so important?
As you already know /if you read the article for MPTT/ using lft and rght values will give possibility to get very easy nested data in various ways.
In Model::find function there is already threaded option, but what about having breadcrumbs?

Here is a way to extend the Model::find function with this functionality. /inspired by Daniel Hofstetter’s post/

<?php
class Category extends AppModel {
    var $name = 'Category';
    var $useTable = 'categories';
    var $actsAs = array('Tree' => 'nested');

    public function find($type, $options = array()) {
        switch ($type) {
            case 'breadcrumbs':
                if(!isset($options['fields']))
                    $options['fields'] = null;
                if(!isset($options['recursive']))
                    $options['recursive'] = null;
                if(is_object($this->Behaviors->Tree) && $options['id']){
                    return $this->Behaviors->Tree->getpath($this, $options['id'], $options['fields'], $options['recursive']);
                } else {
                    return null;
                }
                break;
            default:
                return parent::find($type, $options);
        }
    }
}
?>

As you can see I am using the function TreeBehavior::getpath. There are a lot of handy functions in this behavior, but for breadcrumbs example this is just enough.

How to use it?

$this->Category->find('breadcrumbs', array('id'=>1));

so if you have data like this:

1 Root
2     Cat1
3         Cat1.1
4     Cat2

and use the function mentioned above with id=3 the result will be:

Array
(
    [0] => Array
        (
            [Category] => Array
                (
                    [id] => 1
                    [parent_id] =>
                    [name] => Root
                    [lft] => 1
                    [rght] => 8
                )
        )

    [1] => Array
        (
            [Category] => Array
                (
                    [id] => 2
                    [parent_id] => 1
                    [name] => Cat1
                    [lft] => 2
                    [rght] => 5
                )
        )

    [2] => Array
        (
            [Category] => Array
                (
                    [id] => 3
                    [parent_id] => 2
                    [name] => Cat1.1
                    [lft] => 3
                    [rght] => 4
                )
         )
)

After this with

$breadcrumbs = Set::extract('/Category/name', $result);
echo ' / '.implode(' / ', $breadcrumbs);

you will have the following result

/ Root / Cat1 / Cat1.1

I am leaving to you the styling of it as well as adding the links to the parent nodes.

Share it:
  • Facebook
  • Twitter
  • Digg
  • StumbleUpon
  • del.icio.us
  • Google Bookmarks
  • Yahoo! Buzz
  • Add to favorites
  • Identi.ca

Using more than one database connection in CakePHP

Probably is pretty obvious for most of the advanced users, but when I started my experience with CakePHP I read a lot of configuring a database, but not multiple ones. There are articles how to use database for development and for production without changing anything but rewriting a function in DATABASE_CONFIG class.

These days we need to choose way of splitting the functionality and we have to decide: Shall we use different databases or shall we put a prefix for every table. So far we choose to use prefix, but I dig into this and I realized that every model could be attached to different database.

Here is the example how to do this:
Continue reading

Share it:
  • Facebook
  • Twitter
  • Digg
  • StumbleUpon
  • del.icio.us
  • Google Bookmarks
  • Yahoo! Buzz
  • Add to favorites
  • Identi.ca