2014-01-28 4 views
5

мы часто имеем дело с кодом, который выглядит следующим образом:Каким образом можно правильно встраивать пользовательские поля в запрос поиска CakePHP?

return $this->find(
'all', [ 
    'fields' => ['DISTINCT Tag.tag', 'COUNT(Tag.tag) as count'], 
    'group' => ['Tag.tag'], 
    'order' => ['count' => 'DESC'] 
]); 

Этот запрос приводит нас к следующему выходу:

[0] => Array 
    (
     [Tag] => Array 
      (
       [tag] => walls.io 
      ) 

     [0] => Array 
      (
       [count] => 15 
      ) 

    ) 

Как вы можете видеть, этот запрос возвращает результаты в «как-то не так». Поле «count», к сожалению, помещается в псевдо-[0] -аррей.

IIRC, CakePHP использует внутренний синтаксис, например Tag__field, для правильного вложения виртуальных полей.

При изменении кода в модели __- синтаксиса, проблема остается той же:

return $this->find(
'all', [ 
    'fields' => ['DISTINCT Tag.tag', 'COUNT(Tag.tag) as Tag__count'], 
    'group' => ['Tag.tag'], 
    'order' => ['COUNT(Tag.tag)' => 'DESC'] 
]); 

Выход:

[0] => Array 
    (
     [Tag] => Array 
      (
       [tag] => walls.io 
      ) 

     [0] => Array 
      (
       [Tag__count] => 15 
      ) 

    ) 

Обход 1: array_map

CakePHP плюсы: Есть там лучшее/более элегантное решение, чем ручное сопоставление массива после оператора select?

$tags = array_map(function($tag) { 
    $tag['Tag']['count'] = $tag[0]['count']; 
    unset($tag[0]); 

    return $tag; 
}, $tags); 

Обход 2: виртуальное поле

Как описано выше, использование виртуального поля может решить эту проблему:

$this->virtualFields = ['count' => 'COUNT(Tag.Tag)']; 
return $this->find(
'all', [ 
    'group' => ['Tag.tag'], 
    'order' => [$this->getVirtualField('count') => 'DESC'] 
]); 

К сожалению, с этим решением, это не представляется возможным укажите ЛЮБЫЕ поля. только полностью покидая «поля» -key, вложение массива работает так, как ожидалось. при выборе $ fields = ['Tag.tag', $ this-> getVirtualField ('count')] повторное вложение неверно.

CakePHP pros: Знаете ли вы метод, в котором вложенность выполняется правильно, даже если вы указываете свои собственные поля?

+0

Я пробовал все, что вы упоминали ... И никто из них не работает ... Я снова посмотрю. – Anubhav

ответ

2

Рассматривая код CakePHP, такой метод не существует.

Посмотрите на файл lib/Cake/Model/Datasource/Database/Mysql.php.

Найти метод: Mysql::resultSet($results); (около line 240).

Этот метод отображает результат в массив. Чтобы определить, является ли столбец частью таблицы или нет, он использует PDOStatement::getColumnMeta(). Для вашего «виртуального столбца», что метод возвращает пустую таблицу и поэтому код CakePHP будет поставить его отдельно, см else ветви

$this->map[$index++] = array(0, $column['name'], $type);

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

Итак, вы остаетесь с решением array_map или можете попробовать перегрузить этот класс Mysql и добавить свою собственную логику в том, как определить, где находится столбец.