2014-01-14 4 views
3

Я имеюCakePHP, как создать виртуальное поле на основе другого виртуального поля

Contact Table : id, first_name, last_name, company_id 
Company Table : id, name 

Я хотел бы создать виртуальное поле в контактном таблице, поэтому оно «contactInCompany»

"first_name last_name - Company.name" e.g: Andre Robin - Google 

Как я могу для этого я стараюсь, но он не работает, он не принимает другое виртуальное поле в качестве входных данных

public $virtualFields = array(
    'companyName' => 'SELECT name FROM companies where id = Contact.company_id', 
    'customerWithCompany' => "CONCAT(Contact.first_name, ' ', 
           Contact.last_name, ' ', Contact.companyName, '')"  
    ); 

Я также попытался это так, и это не работает

'customerWithCompany' => "CONCAT(Contact.first_name, ' ', Contact.last_name, '-', 
         SELECT name FROM companies where id = Contact.company_id)" 

мне это нужно довольно часто, я буду использовать это, чтобы положить в ниспадающем переключателе, чтобы выбрать контакт, так что я хотел бы иметь имя контакта, показанное вместе с компания

+0

Вы назначили ассоциации для всех этих моделей должным образом? Я имею в виду, вы указали индексы? – Fury

ответ

8

Вы не можете сделать это с помощью виртуальных полей в качестве ключей в виртуальных полях лишь псевдоним

Пример:

class Contact extends AppModel { 

    public $virtualFields = array(
     'companyName' => 'SELECT name FROM companies where id = Contact.company_id', 
     'customerWithCompany' => "CONCAT(Contact.first_name, ' ', 
           Contact.last_name, ' ', Contact.companyName, '')"  
     ); 

    public function getContacts() { 
     return $this->find('all', array(
        'fields'=>array(
          'Contact.id', 
          'Contact.first_name', 
          'Contact.companyName', 
          'Contact.customerWithCompany' 
          ) 
        ) 
       ); 
    } 

} 

Если getConta Метод КТС() вызывается из ContactsController

Приведенный выше код будет формировать этот запрос:

SELECT Contact.id, Contact.first_name, 
     (SELECT name FROM companies where id = Contact.company_id) AS Contact__companyName, 
     CONCAT(Contact.first_name, ' ', Contact.last_name, ' ', Contact.companyName, '') AS Contact__customerWithCompany 
FROM contacts AS Contact; 

Этот запрос не будет выполнен на MySQL, поскольку это не возможно, чтобы получить доступ к псевдоним 1 колонки для другого колонка.

Для достижения этой цели вам придется использовать подзапросы, как показано ниже: Cake PHP преобразует виртуальные поля имя для Model__ (В приведенном ниже примере это Contact__)

SELECT 
SubQuery.id, 
SubQuery.first_name, 
SubQuery.Contact____companyName, 
CONCAT(SubQuery.first_name, ' ', SubQuery.last_name, ' ', SubQuery.Contact____companyName, '') AS Contact__customerWithCompany 

FROM 
(SELECT Contact.id, Contact.first_name, (SELECT name FROM companies where id = Contact.company_id) AS Contact__companyName 
FROM contacts AS Contact) AS SubQuery; 

Если вы хотите построить вспомогательный запрос в использовании PHP торт buildStatement Метод DataSource

Примечание: Использование присоединяется еще одно лучшим решением для вышеупомянутого запроса, чтобы достичь тех же результатов без использования вложенных запросов.

С Соединения:

public function getContacts() { 
    $this->virtualFields['customerWithCompany'] = "CONCAT(Contact.first_name, ' ', Contact.last_name, ' ', Company.name)"; 
    return $this->find('all', array(
      'fields'=>array(
       'Contact.id', 
       'Contact.first_name', 
       'Contact.last_name', 
       'Company.name', 
       'Contact.customerWithCompany' 
      ), 
      'joins'=>array(
       array(
        'table'=>'companies', 
        'alias'=>'Company', 
        'type'=>'LEFT', 
        'conditions'=>array(
         'Contact.company_id = Company.id' 
        ) 
       ) 
      ) 
     ) 
    ); 
} 
+0

Я не совсем понимаю, как использовать подзапрос или присоединиться. не могли бы вы объяснить это? – Harts

+0

@Harts: Я задал способ использования торта php с использованием объединений.Вам не нужно объявлять виртуальное поле в верхней части модели, если вы не хотите этого в каждом запросе. Создавайте виртуальные поля «на лету», как показано выше. – Hrishi

0

В вашей Concact модели просто попробуйте й следующее:

public $belongsTo = array('Company'); 

public $actsAs = array('Containable'); 

public $virtualFields = array(
    'customerWithCompany' => "CONCAT(Contact.first_name, ' ', 
           Contact.last_name, ' ', Company.name, '')"  
    ); 

и в контроллере сделать что-то вроде:

$this->Contact->find(
    'list', 
    array(
     'fields' => array('Contact.id', 'Contact.customerWithCompany'), 
     'contain' => array('Company') 
    ) 
); 
+0

не работает. Столбец не найден: 1054 Неизвестный столбец 'Company.name' в 'списке полей' – Harts

+0

попробуйте установить recursive = 2 в вашем поиске – arilia

+0

это не работает. – Harts

1

В вашей модели контакта написать следующее:

public $belongsTo = array(
     'Company' => array(
      'className' => 'Company', 
      'foreignKey' => 'company_id', 
      'conditions' => '', 
      'fields' => '', 
      'order' => '' 
     ) 
    ); 

В компании модели пишут:

public $hasMany = array(
      'Contact' => array(
       'className' => 'Contact', 
       'foreignKey' => 'company_id', 
       'dependent' => false, 
      ), 
    } 

Теперь при поиске любого Контакта он будет содержать информацию о соответствующей компании тоже. Распечатайте массив, и вы увидите индекс .

PS: Если у меня есть неправильный вопрос, сообщите мне точную проблему, я могу помочь вам.

+0

Я хотел бы использовать это как поле отображения. например: если я делаю $ contactInCustomer = $ this-> Contact-> find ('list'). Он должен дать мне массив со значением, что-то вроде «Contact.first_name Contact.last_name Company.name». У меня есть все, что принадлежит To и отношения hasMany уже настроены. Мне просто нужно получить возвращаемый результат результата данных, как указано, и это данные 2000ish, я не хочу делать вручную каждый цикл. – Harts

0

Я не уверен, но попробуйте установить свои виртуальные поля в соответствующий конструктор моделей.

2

Вам не нужен виртуальный экран. Используйте JOIN LEFT для этого простого запроса.

$users= $this->Contact->query('SELECT CONCAT(first_name," ",last_name," - ", companies.name) AS customerWithCompany FROM users 
          LEFT JOIN companies on contact.company_id = companies.id'); 

читать данные:

  $userList = array(); 
      foreach ($users as $user) { 
       $userList[] = $user[0]['customerWithCompany']; 
      } 

      var_dump($userList); 

выход:

array(
     (int) 0 => 'Harts Jackson - Google' 
     (int) 1 => 'Emo Rock - Yahoo' 
      ... 
) 

А также реализация virtualFields имеет несколько ограничений. Сначала вы не можете использовать virtualFields для связанных моделей для условий, порядка или массивов полей. Это приведет к ошибке SQL, поскольку поля не заменяются ORM. Это связано с тем, что трудно оценить глубину, на которой может быть найдена соответствующая модель.

Если у вас нет связанных моделей (которые, как я вижу, у вас есть, и вы хотите назначить условие), вам необходимо создать метод конструктора в вашей модели контактов и установить свой virtualFiled в конструкторе. здесь How to create $virtualFields

0

это не предмет, но это виртуальное поле с соответствующими моделями работы:


Orderitem hasMany Necessary 
Necessary hasMany Recipe 
Necessary hasMany Storage 

'inrecipe' => 'SELECT COUNT(Necessary.id) 
     FROM necessaries AS Necessary 
     INNER JOIN recipes AS Recipe 
     ON Necessary.recipe_id = Recipe.id 
     WHERE Orderitem.id = Necessary.orderitem_id ', 

это тоже работает



'instorage' => 'SELECT COUNT(Necessary.id) 
     FROM necessaries AS Necessary 
     INNER JOIN recipes AS Recipe 
     ON Recipe.id=Necessary.recipe_id 
     INNER JOIN storages AS Storage 
     ON Storage.id=Necessary.storage_id 
     AND Recipe.quantity = Storage.quantity 
     WHERE Orderitem.id = Necessary.orderitem_id ', 

и сложнее ...



'resolution' => 'SELECT IF(
     (SELECT COUNT(Necessary.id) 
     FROM necessaries AS Necessary 
     INNER JOIN recipes AS Recipe 
     ON Recipe.id=Necessary.recipe_id 
     INNER JOIN storages AS Storage 
     ON Storage.id=Necessary.storage_id AND Recipe.quantity=Storage.quantity 
     WHERE Orderitem.id = Necessary.orderitem_id) 
     = 
     (SELECT COUNT(Necessary.id) 
     FROM necessaries AS Necessary 
     INNER JOIN recipes AS Recipe 
     ON Necessary.recipe_id = Recipe.id 
     WHERE Orderitem.id = Necessary.orderitem_id) 
     ,"YES", "NO") ', 

Смежные вопросы