#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, но я думаю, что преобразование объекта в массив не обязательно должно быть специфичной для фреймворка проблемой