0

I have models Person and Phone/Email with HABTM relationship. After some pain I found out, that my life is easier, when I break HABTM into: Person hasMany PeoplePhone, Phone hasMany PeoplePhone, PeoplePhone belongsTo (Person,Phone). Well, I don't need any help with this :-) now, my problem is different:

Before I can pair Person with his Phone or Email, I need to save this Phone/Email and then get its ID.

Now I would like to save only unique Phones and unique Emails, so I have created this method in app_model.php:

function saveUnique($data = null, $unique_fieldname = null)
{
    if (! $data) { return false; }
    if (! $unique_fieldname) { return false; }

    $id = $this->field('id', array($unique_fieldname => $data[$this->name][$unique_fieldname]));

    if ($id)
    {
        $this->read(null, $id);
    }
    else
    {
        $this->create();
        $this->set($data);
        if (! $this->validates()) { return false; }
        if (! $this->save()) { return false; }
    }        
    return true;
}

It seems to work, but I am all new to CakePHP. How would CakePHP guru solve this function/method?

Thank you very much for your time.

-Petr

Petr Cezar
  • 159
  • 2
  • 8

2 Answers2

1

If I were you, I would stick with default Cake functionality rather than what you are doing. All of this functionality is built into Cake, so why reinvent the wheel?

First, HABTM relationships already work as you have broken them out. You can access the join models by adding with in your model associations. This should give you access to the intersection table data.

$hasAndBelongsToMany =  array(
    'Phone' => array(
        'className'              => 'Phone',
        'joinTable'              => 'persons_phones',
        'foreignKey'             => 'person_id',
        'associationForeignKey'  => 'phone_id',
        'unique'                 => false,
        'with'           => 'PersonsPhones'
    )
);

As far as your unique phone and email requirements go, why not use Cake's built in validation to do the checking for you? That way, you just call the save function and then Cake will do all the checking for you.

For instance, if a person only has one email address, then do this in the person model. This will validate that the input is an email address and that it is a unique email address in the database. You can do this validation with any field and build custom validation rules with ease.

public $validate = array(
    'email' => array(
        'email' => array(
            'rule' => 'email',
            'message' => 'You must enter an email address.'
        ),
        'isUnique' => array(
            'rule' => 'isUnique',
            'message' => 'An account with this email address already exists.'
        )
    )
);

I take it that there is a reason for why you would use HABTM for an email address. Normally, people would not share email addresses, so hasMany would probably be a better relationship. I can see it working for phone as people do share phone numbers frequently. I say this so that you are sure that HABTM is the relationship you really want to use.

Scott Harwell
  • 7,457
  • 2
  • 28
  • 41
  • Well, the "with" thing is new to me. I'll try it out, thank you. I don't remember all the problems I had when I was fighting with native HABTM functionality, but, for example, what if I want to add only one more phone number to a person? Is there a way to do it? It always removed all previously saved relations in people_phones table. – Petr Cezar Jun 06 '11 at 12:34
  • the "unique" property in the HABTM relationship prevents the model from overwriting previous records, so it will behave more like a regular model if you set unique to false. – Scott Harwell Jun 06 '11 at 12:45
0

I've only been using CakePHP for a couple months but I would implement it a little different.

I'd add a UNIQUE index on person_id & email_id in my PeopleEmail table (do the same thing in PeoplePhone). This way we're not accidentally saving duplicate data, our physical schematic prevents duplicate records before they're even stored.

Now we just have to keep an eye out for the SQL error being thrown. I haven't dug too deep into this aspect of Cake yet but I do know the base AppModel class has an onError() method that may provide useful in this regard.

Charles Sprayberry
  • 7,741
  • 3
  • 41
  • 50
  • This doesn't do proper validation though. While the end result is the same (data will not save because of a MySQL error), the CakePHP validator will achieve the same thing and allow you to use the debug and notification systems within cake to alert the user that a record already exists. – Scott Harwell Jun 06 '11 at 12:50