Объект CakePHP 2.0 не массив

#php #arrays #cakephp #object #cakephp-2.0

#php #массивы #cakephp #объект #cakephp-2.0

Вопрос:

В настоящее время я новичок в CakePHP и поиграл с CakePHP 1.3, но недавно был выпущен CakePHP 2.0.

Пока мне это нравится, но единственное, что вызывает беспокойство, это тот факт, что он не возвращает объекты, а просто возвращает массивы. Я имею в виду, вряд ли имеет смысл делать $post[‘Post’][‘id’] . (на мой взгляд) гораздо практичнее просто сделать $post->id .

Однако после Google я наткнулся на эту ссылку, которая продолжала генерировать ошибки о том, что индексы не были определены при использовании класса Form (предполагаю, это связано с тем, что он получал объективированную версию, а не версию массива).

Я следую руководству по блогу (уже следил за ним в версии 1.3, но повторяю его для версии 2.0)

Итак, кто-нибудь знает, как добиться этого, не мешая классу Form?

Хош

Ответ №1:

Малоизвестный факт: Cake возвращает их как объекты или, во всяком случае, свойства объекта.Массивы являются синтаксическим сахаром:

     // In your View:
    debug($this->viewVars);
 

Shwoing — это $this объект представления, и viewVars свойство соответствует $this->set('key', $variable) или $this->set(compact('data', 'for', 'view')) из действия контроллера.

Проблема с их $Post->id сжатием ради нажатий клавиш — это торт, вот почему. Cake спроектирован как тяжеловес, поэтому его встроенный ORM смехотворно мощный, неизбежный и предназначенный для обращения к бесконечным строкам бесконечно связанных таблиц — автоматические обратные вызовы, автоматическая передача данных, генерация запросов и т. Д. Базовая глубина многомерных массивов зависит от вашего метода поиска, как только вы работаете с более чем одним $Post с несколькими связанными моделями (например), вы ввели массивы в микс, и этого просто не избежать.

Разные find методы возвращают массивы разной глубины. Из сгенерированного по умолчанию кода контроллера вы можете видеть, что index использует $this->set('posts', $this->paginate()); — view использует $this->set('post', $this->Post->read(null, $id)); и edit вообще не использует $this->set Post find — он присваивает $this->data = $this->Post->read(null, $id); .

FWIW, Set::map вероятно, выдает эти undefined index ошибки, потому что (предполагаю) вы пытаетесь сопоставить действие редактирования, амирите? По умолчанию действия редактирования используются только $this->set для установки связанных находок модели в представление. Вместо этого отправляется результат $this->read $this->data . Вероятно, поэтому Set::map не работает. В любом случае, вы все равно будете стремиться к $Post[0]->id or $Post->id (в зависимости от того, какой метод вы нашли, который вы использовали), что не является большим улучшением.

Вот несколько общих примеров глубины свойства Set::map() для этих действий:

     // In posts/index.ctp
    $Post = Set::map($posts);
    debug($Post);
    debug($Post[0]->id);

    // In posts/edit/1
    debug($this-viewVars);
    debug($this->data);

    // In posts/view/1
    debug($this-viewVars);
    $Post = Set::map($post);
    debug($Post->id);
 

http://api13.cakephp.org/class/controller#method-Controllerset

http://api13.cakephp.org/class/model#method-Modelread

http://api13.cakephp.org/class/model#method-ModelsaveAll

HTH.

Ответ №2:

Вы можете создать дополнительные переменные объектов. Таким образом, вы не будете вмешиваться в автоматическую работу Cake, но сможете получить доступ к данным, используя формат, подобный $modelNameObj-> id; format .

Во-первых, создайте AppController.php в /app/Controller, если у вас его еще нет. Затем создайте функцию beforeRender(). Это будет искать данные в стандартных соглашениях об именовании Cake и создавать из них дополнительные переменные объектов.

 <?php
App::uses('Controller', 'Controller');

class AppController extends Controller {

  public function beforeRender() {

    parent::beforeRender();

    // camelcase plural of current model
    $plural = lcfirst(Inflector::pluralize($this->modelClass));

    // create a new object
    if (!empty($this->viewVars[$plural])) {      
      $objects = Set::map($this->viewVars[$plural]);
      $this->set($plural . 'Obj', $objects);     
    }

    // camelcase singular of current model
    $singular = lcfirst(Inflector::singularize($this->modelClass));    

    // create new object 
    if (!empty($this->viewVars[$singular])) {      
      $object = Set::map($this->viewVars[$singular]);
      $this->set($singular . 'Obj', $object);
    }
  }
}
 

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

index.ctp

 $productsObj;
 

просмотр.ctp

 $productObj->id;
 

Все, что мы делаем, это добавляем ‘Obj’ к именам переменных, которые Cake уже предоставит. Некоторые примеры сопоставлений:

Продукты -> $productsObj

ProductType -> $productTypesObj

Я знаю, что это не идеально, но это по существу достигло бы того, чего вы хотели, и было бы доступно во всех ваших моделях.

Комментарии:

1. Это сработало! Спасибо! Вероятно, это не идеально, как вы сказали, но таким образом у меня будет доступ как к массиву, так и к версии объекта, если мне это как-то понадобится! Спасибо

Ответ №3:

Хотя мне нравится идея, предложенная Moz, существует ряд существующих решений этой проблемы.

Самый быстрый, который я нашел, это https://github.com/kanshin/CakeEntity — но, похоже, вам, возможно, потребуется реорганизовать его для 2.x — возможно, даже уже существует ветвь или форк 2.x, но я не смотрел.

Комментарии:

1. Существует ветка 2.0, которая была обновлена с использованием соглашений CakePHP 2.0 об именах файлов и т. Д.

Ответ №4:

Я также пару раз задавал этот вопрос в своей голове. Теперь, спустя несколько приложений на основе Cake, я вижу преимущество в возможности разветвлять и объединять (am, in_array и т. Д.) результирующие наборы удобнее с массивами, Чем с использованием объектов. Форма $Post-> id была бы приятным синтаксическим сахаром, но не реальным преимуществом по сравнению с массивами.

Комментарии:

1. Ценю ваш вклад, но на самом деле это не ответ на мой вопрос :/

2. Я просто хотел указать, что вы пытаетесь сделать это неправильно. Ассоциативные массивы — это правильный путь.

Ответ №5:

Вы могли бы написать функцию, которая выполняет итерацию по вашим общедоступным свойствам (см. ReflectionClass::GetProperties ) и сохранить ее в массиве (и вернуть массив).

Если у вас есть доступ к классу, вы можете реализовать интерфейс ArrayAccess и легко получить доступ к вашему объекту в виде массива.

PS: Извините, я никогда не использовал CakePHP, но я думаю, что преобразование объекта в массив не обязательно должно быть специфичной для фреймворка проблемой