Rene Polo
Rene Polo

Reputation: 831

How to use virtualFields in a model with different aliases?

well the main problems involves two Models, USER and MESSAGE, they have a relationship because what message does is the following:

Messages can be sent by the Users to other users.. so i have to identify who is the sender and who is te receiver, and im doing it by setting two Model Aliases to USER, which are 'Sender' and 'Receiver' (like this).

//This is on User model
'MessageSender' => array(
        'className' => 'Message',
        'foreignKey' => 'sender_id'
    ),
    'MessageRecipient' => array(
        'className' => 'Message',
        'foreignKey' => 'recipient_id'
    ),

and the relationship in Messages is something like this.

public $belongsTo = array(
    'Recipient' => array(
        'className' => 'User',
        'foreignKey' => 'recipient_id'
    ),
    'Sender' => array(
        'className' => 'User',
        'foreignKey' => 'sender_id'
    )
);

Up to here everything is fine..

Whenever i have to create a message i have a dropdown that shows me the complete list of the user first_names, but because i need to know everyone's last_name i've created a $virtualField to join them (first_name and last_name) like this.

//this is located on the USER model
public $virtualFields = array(
    'fullname' =>   'CONCAT(Recipient.first_name, " ", Recipient.last_name)'
);

How i am using the Users in the message creation? well i'm using the person who is going to send a new message as the Sender, so the Sender is the user's id and the Receiver is the selected user in the drop down...

Selecting the Receiver

the main problem is when i try to access any other part of the website that references the USER model, it throws me this error:

Database Error
Error: SQLSTATE[42S22]: Column not found: 1054 Unknown column 'Recipient.first_name' in 'field list'

and of course is because my virtualField is expecting a result from the 'Recipient.first_name' and 'Recipient.last_name' to join them together, but because i'm not using Recivers and Senders all the time... (because those are just for the Message model usage) it throws me an error
How should i handle this? is there any way i can put any conditional (if else) so the User model will not to use

User.first_name

and instead use

Receive.first_name

or vice versa?

if you need any other information please ask, i'll be very thankful, Best Regards!

Upvotes: 1

Views: 102

Answers (2)

AgRizzo
AgRizzo

Reputation: 5271

There is a 3rd way also: dynamically construct the virtual field, taking into consideration the alias that your model is being referenced as.

public function __construct($id = false, $table = null, $ds = null) {
    parent::__construct($id, $table, $ds);
    $this->virtualFields['fullname'] = sprintf("CONCAT(%s.first_name, ' ', %s.last_name)", 
            , $this->alias, $this->alias);
}

With this technique, you can use:

  • User.fullname
  • Sender.fullname
  • Recipient.fullname

Upvotes: 2

marian0
marian0

Reputation: 3327

Ok, you can do this two ways. First, you can define this virtual field on the fly, before your find():

$this->YourModel->virtualFields = array('fullname' => 'CONCAT(Recipient.first_name, " ", Recipient.last_name)');
$this->YourModel->find(...);

or (if you have more virtual fields)

$this->YourModel->virtualFields['fullname'] = 'CONCAT(Recipient.first_name, " ", Recipient.last_name)';
$this->YourModel->find(...);

The second way, which is more flexible for future, you can append this virtual field in beforeFind() callback basing on some switch variable. So before your find query you can activate a switch and this virtual field will be appended to query.

class YourModel extends AppModel {
    private $_fullNameEnabled = false;

    public function beforeFind($queryData) {
        parent::beforeFind($queryData);

        if (!empty($this->_fullNameEnabled)) {
            $this->virtualFields = array('fullname' => 'CONCAT(Recipient.first_name, " ", Recipient.last_name)');
        }

        return $queryData;
    }

    public function fullnameFieldStatus($status = true) {
        $this->_fullNameEnabled = $status;
    }
}

And then before you call find() use:

$this->YourModel->fullnameFieldStatus();

Upvotes: 2

Related Questions