2015-01-07 1 views
1

в моем проекте CakePHP 2.0 у меня есть эта модель сценария (следуют псевдо-код):ребенок отношение объекта внутри родителя на CakePHP найти

model Product { 
    int id; 
    Video video; 
} 

model Video { 
.... 
} 

Я хочу использовать CakePHP $ this-> Product-> найти ('all'), чтобы получить все мои продукты и связанные видео. CakePHP дают мне результаты в многомерном массиве таким образом:

{ 
    Product: { 
     id: "3", 
     video_id: "1", 
    }, 
    Video: { 
     id: "1", 
     url: "c", 
}, 
{ 
    Product: { 
     id: "3", 
     video_id: "1", 
    }, 
    Video: { 
     id: "1", 
     url: "c", 
} 

Как я могу получить видео (дочерний объект) внутри родительского продукта, таким образом:

{ 
    Product: { 
     id: "3", 
     video_id: "1", 
     Video: { 
     id: "1", 
     url: "c", 
     } 
} 

Я знаю, что именно этот случай его легко создать новый массив, потому что theres только два объекта, но есть ли все равно, чтобы сделать этот автоматический для больших отношений, может cakephp обрабатывать это?

+0

Ваш scenraio полно ложно. Вы не можете поместить класс модели в другую модель. Подробнее: http://book.cakephp.org/2.0/ru/models/associations-linking-models-together.html и http://book.cakephp.org/2.0/ru/models/retrieving-your-data .html –

+0

Благодарим за отзыв. Код, который я показал, - это просто псевдокод. В cakephp вам нужно наладить отношения, но представление того, что архивировано «hasone» и «принадлежит», является именно тем, что я показал. Мне нужно это представление (объект внутри объекта), потому что мне нужно экспортировать json для других plataforms (android/ios), а по умолчанию для моделей в них есть дочерний родительский. – sagits

+0

В вашем примере Продукт принадлежит видео, потому что таблица продуктов имеет внешний ключ. Таким образом, продукт является дочерним элементом видео, но не наоборот. – bancer

ответ

2

Попробуйте этот подход. Переопределить значение по умолчанию find('all'), чтобы он принял пользовательский параметр, что позволит переформатировать результаты. Поместите это в AppModel, поэтому она доступна для всех моделей

Edited база по требованию от комментариев, чтобы удалить пустые ассоциации и совместные данные для HABTM ассоциаций из переформатирован результата:

class AppModel extends Model 
{ 
    protected function _findAll($state, $query, $results = array()) 
    { 
     if ($state === 'before') { 
      return $query; 
     } 

     if (isset($query['reformat']) && $query['reformat'] === true) { 
      foreach ($results as &$_result) { 
       reset($_result); 
       $modelName = key($_result); 
       $modelPart = array_shift($_result); 

       if (!empty($query['filter']) && is_array($query['filter'])) { 
        $this->recursive_unset($_result, $query['filter']); 
       } 

       $_result = array(
        $modelName => array_merge($modelPart, $_result) 
       ); 
      } 
     } 

     return $results; 
    } 

    public function getHabtmKeys() { 
     $habtmKeys = array(); 
     // 1. level inspection 
     foreach ($this->hasAndBelongsToMany as $name) { 
      $habtmKeys[] = $name['with']; 
     } 
     // 2. level inspection 
     $allAsssoc = array_merge(
      $this->belongsTo, 
      $this->hasMany, 
      $this->hasOne 
     ); 
     foreach ($allAsssoc as $assocName => $assocVal) { 
      foreach ($this->$assocName->hasAndBelongsToMany as $name) { 
       $habtmKeys[] = $name['with']; 
      } 
     } 

     return $habtmKeys; 
    } 

    private function recursive_unset(&$array, $keys_to_remove) { 
     foreach ($keys_to_remove as $_key) { 
      unset($array[$_key]); 
     } 

     foreach ($array as $key => &$val) { 
      if (is_array($val)) { 
       if (empty($val) || (!isset($val[0]) && empty($val['id']))) { 
        unset($array[$key]); 
       } else { 
        $this->recursive_unset($val, $keys_to_remove); 
       } 
      } 
     } 
    } 
} 

Для удаления пустых ассоциаций и HABTM совместные данные, я использовал recursive unset procedure в сочетании с осмотр ассоциаций для соответствующей модели. Я не смог достичь этого с помощью конфигурации find, содержать или любым другим способом.

Следующей array_shift($_result) делит $_result массива на две части - основной модели, на которой find был запущен (это всегда первый ключ в результате) и остальных (все ассоциации), то он объединяет эти массивы в соответствии с лицензией ключ основной модели. Конечно, это переформатирует результаты только на первом уровне, но на более глубоких уровнях ассоциации связаны по умолчанию, поэтому вам не нужно заботиться об этом.

Теперь используйте find('all'), как всегда, но предоставьте пользовательские параметры reformat и filter. Если вы их не предоставите, результат будет получен в формате по умолчанию.

  • filter является массив ключей, которые будут удален из результата

  • getHabtmKeys() динамически получает массив ключей HABTM ассоциаций для модели (только 1. и 2. ассоциаций уровня, может быть дополнительно модифицирован, чтобы проверить, даже Глубже).

Использование:

// To nest child associations in parent 
$this->Product->find('all', array(
    'reformat' => true 
)); 
// To remove also joint data for HABTM and empty associations 
$this->Product->find('all', array(
    'reformat' => true, 
    'filter' => $this->Product->getHabtmKeys(),   
)); 
// Keys to remove can be also manually added 
$this->Product->find('all', array(
    'reformat' => true, 
    'filter' => array_merge($this->Product->getHabtmKeys(), 'SomeExtraKey'), 
)); 

Смотрите также: Retrieving Your Data > Creating custom find types

+0

Спасибо, он почти сработал. Я пробовал с продажей sagits

+0

@sagits i обновил свой ответ, проверьте его, теперь он также должен удалить дополнительные данные HABTM и пустые ассоциации. –

+0

Perfect. Кстати, я нашел плагин, который меняет find для извлечения объектов, но я предпочитаю ваш путь, потому что плагин перекрывает некоторые функции по умолчанию, и я все равно добавлю его к вашему ответу. Спасибо вам за помощь. – sagits

2

Это будет работать, чтобы получить каждое видео ребенок в каждом продукте в FindAll

$products = $this->Product->find('all') 

foreach($products as $product) { 
    echo $product["Video"]["url"]; 
} 
+0

Спасибо за ответ. В этом примере его легко подталкивать один массив к другому, я мог бы просто загрузить $ product ["Video"] внутри $ product ["Product"]. Но тогда мне придется делать это вручную во всех моих моделях. Im после того, как сделать это автоматически для всех моих моделей. – sagits

2

Путь Cake возвращает объект является правильным, поскольку это обращается объединение и возвращает данные внутри основного объекта поиска.

Объект внутри объекта, о котором вы говорите, происходит, если у вас есть более глубокий уровень рекурсии или вы используете сдерживаемые для доступа к более глубоким отношениям.

Например

$this->Product->find('all'); 

возвращение будет объект как

array(
    'Product' => array(
    'id' => '3', 
    'video_id' => '1', 
), 
    'Video' => array(
    'id' => '1', 
    'url' => c, 
), 
) 

Расположение объекта ваш являются после того, как происходит только тогда, если есть hasMany или HABTM присоединиться на этой модели или изменить уровень или используйте сдерживаемое, чтобы затем изучить отношения для объединенной модели.

я надеюсь это сделал.

+0

Спасибо за ответ. Но по hasmany и HABTM он по-прежнему показывает 2 отдельных массива (по одному на тип объекта). Могу ли я архивировать видео-массив внутри продукта с помощью сдерживаемого? как? – sagits

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