Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

cakePHP hasOne empty

Tags:

mysql

cakephp

I'm new to cakePHP and I have a Problem with Relations.

My Model Looks like this:

<?
class Operator extends AppModel
{
    var $name = 'Operator';
    var $hasOne = array('Contact','Adress','Land');
}
?>

and my Table Looks like this:

CREATE TABLE `operators` (
  `id` varchar(45) NOT NULL,
  `name` int(11) NOT NULL,
  `adress_id` int(11) NOT NULL,
  `land_id` int(11) NOT NULL,
  `contact_id` int(11) NOT NULL,
  `operator_category_id` int(11) NOT NULL,
  `legal_form` varchar(45) DEFAULT NULL,
  `affidavit` varchar(45) DEFAULT NULL,
  `comment` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `id_UNIQUE` (`id`),
  KEY `operator_category_fk_idx` (`operator_category_id`),
  KEY `contact_id_idx` (`contact_id`),
  KEY `adress_id_idx` (`adress_id`),
  KEY `land_id_idx` (`land_id`),
  CONSTRAINT `adress_id` FOREIGN KEY (`adress_id`) REFERENCES `adresses` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION,
  CONSTRAINT `contact_id` FOREIGN KEY (`contact_id`) REFERENCES `contacts` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION,
  CONSTRAINT `land_id` FOREIGN KEY (`land_id`) REFERENCES `lands` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION,
  CONSTRAINT `operator_category_fk` FOREIGN KEY (`operator_category_id`) REFERENCES `operator_category` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION
)

but cakePHP doesn't Show any data from e.g. contacts enter image description here

what am I doing wrong?

like image 427
Raildex Avatar asked Feb 18 '26 17:02

Raildex


2 Answers

hasOne relationship only serves if you have 1 to 1 association to be able to access the associated model within the model which has no foreign key.

belongsTo

In your case, you want to use belongsTo, belongsTo is used as soon as you have a foreign key in your model pointing to another model, your Operator model has foreign keys pointing to Contact, Address, Land which are resp. contact_id, address_id and land_id.

Since the contact_id field is in the Operator model, then the Operator model belongsTo the Contact model.

class Operator extends AppModel {
    public $belongsTo = array('Contact') ;
}

When fetching an Operator entry, you will get something like:

Array(
    [Operator] => Array
        (
            [id] => 42,
            [name] => 'operator',
            [contact_id] => 33
        )
    [Contact] => Array
        (
            [id] => 33,
            [name] => 'contact'
        )
)

hasOne and hasMany

Since your Operator belongsTo Contact, your Contact hasOne OR hasMany Operator. Let's illustrate the difference between the two:

  1. Each of your Contact entry is associated to only one Operator, you could add a operator_id foreign key inside your Contact model but it would be redundant because you already have the association using contact_id in Operator. Thus, what you do is create a hasOne association inside the Contact model, so Contact hasOne Operator.
class Contact extends AppModel {
    public $hasOne = array('Operator') ;
}

Again, when fetching a Contact entry you will get:

Array(
    [Contact] => Array
        (
            [id] => 33,
            [name] => 'contact'
        )
    [Operator] => Array
        (
            [id] => 42,
            [name] => 'operator',
            [contact_id] => 33
        )
)

Note that this is the same as when fecthing an Operator with a belongsTo Contact. The difference between hasOne and belongsTo is mainly which model has a foreign key pointing to the other.

  1. Eah of your Contact entry is associated to multiple (many) Operator, in this case your Contact hasMany Operator.
class Contact extends AppModel {
    public $hasMany = array('Operator') ;
}

Again, the output of $this->Contact->find():

Array(
    [Contact] => Array
        (
            [id] => 33,
            [name] => 'contact'
        )
    [Operator] => Array
        (
            [0] => Array
                (
                    [id] => 42,
                    [name] => 'operator 42',
                    [contact_id] => 33
                )
            [0] => Array
                (
                    [id] => 47,
                    [name] => 'operator 47',
                    [contact_id] => 33
                )
        )
)

hasAndBelongsToMany

Now, assume one Operator can have multiple Contact, and one Contact can serve multiple Operator. In this case, you need an extra table (which should be called operators_contacts if you follow CakePHP naming convention), with two fields operator_id and contact_id:

class Contact extends AppModel {
    public $hasAndBelongsToMany = array('Operator') ;
}
class Operator extends AppModel {
    public $hasAndBelongsToMany = array('Contact') ;
}

The output of $this->Contact->find('all') will be similar to the one using the hasMany relationship, main difference would be that their is no operator_id or contact_id field in the model.


Full example

Let's assume I have the following models: Company, Employee, Address, and the following constraints:

  • A Company has various Employee but only one CEO which is part of its Employee
  • A Company has one Address, and there is at most one company at each Address

You have the following tables:

CREATE TABLE companies (
    id INTEGER AUTO_INCREMENT PRIMARY KEY,
    ceo_id INTEGER REFERENCES employees (id)
) ;

CREATE TABLE employees (
    id INTEGER AUTO_INCREMENT PRIMARY KEY,
    company_id INTEGER REFERENCES companies (id)
) ;

CREATE TABLE addresses (
    id INTEGER AUTO_INCREMENT PRIMARY KEY,
    company_id INTEGER REFERENCES companies (id)
) ;

Note that in this case, you cannot the table with all the constraints because you have a loop between companies and employees, you need to add the constraints after.

And the following CakePHP models:

class Company extends AppModel {

    /* A Company has many Employee. */
    public $hasMany = array('Employee') ;

    /* A Company has one CEO, but the key is in the Company model, 
       so it is a belongsTo relationship. */
    public $belongsTo = array(
        'CEO' => array(
            'className' => 'Employee', // It's an Employee
            'foreignKey' => 'ceo_id'
        )
    ) ;

    /* A Company has one address. */
    public $hasOne = array('Address') ; 

} ;
class Employee extends AppModel {

    /* An Employee belongs to a Company. */
    public $belongsTo = array('Company') ;

} ;
class Address extends AppModel {

    /* An address belongs to a Company. */
    public $belongsTo = array('Company') ;

} ;

Notice I have put a company_id foreign key in the Address model, so Address belongsTo Company and Company hasOne Address, I could have put a address_id inside the Company model and I would have had Company belongsTo Address and Address hasOne Company. I made an arbitrary choice here, in a real application you should think of which of the two above cases is the most meaningful.

Also note that the way I defined my model, there is nothing that prevent an Employee to be the CEO of a Company without being one of its own Employee.


You can find more information in the CakePHP 2.x Book.

like image 180
Holt Avatar answered Feb 21 '26 12:02

Holt


you should you use $belongsTo instead of hasOne relationship for this purpose.

public $belongsTo = array(
        'Contact' => array(
            'className' => 'Contact',
            'foreignKey' => 'contact_id',   // check this
            'conditions' => '',
            'fields' => '',
            'order' => '',
            'counterCache' => true
        )
    );
like image 34
Manoj Dhiman Avatar answered Feb 21 '26 12:02

Manoj Dhiman



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!