Доступ к моделям CodeIgniter в других моделях
Раньше в модели CodeIgniter вы не могли получить доступ к другой модели.
$this->load->model('bar');
$this->bar->something();
Это все еще в силе, или они изменили это?
8 ответов
Это ОЧЕНЬ длинные ответы на простой вопрос.
Краткий ответ: теперь это полностью поддерживается. Перекрестная загрузка, если вам это нравится!
Я категорически не согласен с тем, что "модель" должна инкапсулировать таблицу базы данных только с простыми операциями CRUD. Как отмечено в статье в Википедии:
http://en.wikipedia.org/wiki/Model-view-controller
... этот прикладной уровень призван сделать больше, чем просто действовать как абстракция таблицы единой базы данных. Подумайте о значении слова "контроллер" - оно должно действовать скорее как директор, а не как само приложение. "Модель" - это место для бизнес-логики. Большинство крупномасштабных приложений фактически хранят большую часть своей бизнес-логики в самой базе данных (в форме триггеров, хранимых процедур, внешних ключей и т. Д.).
Я думаю, что неправильное понимание того, что такое "модель", отчасти вызвано той же (чрезмерной) шумихой над "MVC", не имея при этом большого понимания самих концепций. Что-то вроде того, насколько пустой AJAX или, что еще проще, "Web 2.0". К счастью или к сожалению, множество скриптовых детишек запрыгнуло на универсал MVC, и поскольку простые сценарии с практическими рекомендациями и примерами делают не больше, чем просто совет, чтобы вы поместили код вашей базы данных в "модель", неправильное использование этого слоя как только абстракция базы данных стала обычным явлением. Теперь вы читаете сообщения по всему Интернету, называя их "нечистыми", "грязными", "хакерскими", чтобы поместить любую бизнес-логику в модель. Это неверно. Дезинформировали.
Простой пример - подумать о внешних ключах: даже если вы хотите, чтобы ваша "модель" была моделью базы данных, если вы хотите быть "чистой", "правильной" или чем-то еще, вы действительно должны обеспечивать ссылочную целостность в ней., Благодаря отсутствию реальной поддержки внешних ключей в MySQL в течение многих лет веб-приложения росли, и никто не беспокоился о ссылочной целостности вообще. Подходит для сценария детского образа жизни, я думаю. Во всяком случае, даже для того, чтобы даже этот упрощенный вид модели мог поддерживать достоверность внешнего ключа, модель должна работать с другими (или, особенно, если такая среда, как CodeIgniter, не позволяет вам этого делать, вы должны писать запросы другим таблицы, иногда дублирующие запросы в другом месте - это плохой стиль).
Поэтому я считаю, что это недостаток CodeIgniter. Я понимаю, что это может быть нелегко, но это, безусловно, разочаровывающий упущение.
Поэтому я взял приведенный выше пример кода и превратил его в помощника, так что теперь у меня есть функция, которая работает почти идентично обычной функциональности $this->load->model(). Вот оно (поместите его в помощник, который загружается автоматически, и вы можете использовать его в любой модели):
/**
*
* Allow models to use other models
*
* This is a substitute for the inability to load models
* inside of other models in CodeIgniter. Call it like
* this:
*
* $salaries = model_load_model('salary');
* ...
* $salary = $salaries->get_salary($employee_id);
*
* @param string $model_name The name of the model that is to be loaded
*
* @return object The requested model object
*
*/
function model_load_model($model_name)
{
$CI =& get_instance();
$CI->load->model($model_name);
return $CI->$model_name;
}
Это возможно, но не идеально и считается плохим и скорее для "быстрого исправления", чем для идеальной или чистой реализации.
class Location extends Model{
public function get($ID){
// Get main CI object handle and load model
$CI =& get_instance();
$CI->load->model('LocationType');
// Call new model functions using handle to main CI object
$CI->LocationType->setID($result->LocationTypeID);
$CI->LocationType->setTitle($result->TypeTitle);
$this->_locationType = $CI->LocationType;
//Other Stuff
}
}
В любое время, когда вы используете основной объект CI, это плохая идея. Попробуйте переосмыслить свой макет и просто передать данные в / из контроллера на модели.
Вы можете загружать модели из моделей, как говорит Фил Стерджон, но вы должны быть осторожны с зависимостями, если загружаете модели в конструктор моделей: если модель A использует модель B, а модель B использует модель A, когда вы пытаетесь загрузить одну или другой, вы попадете в бесконечный цикл.
В подобных ситуациях в Code Igniter я предпочитаю одну из двух возможностей:
1) Имейте атрибут и сеттер модели следующим образом:
class X extends Model {
var $Y_model;
public function setY($Y) {
$this->Y_model = $Y;
}
public function doItRightNow($a,$b) {
$list = $this->Y_model->getSomeList($a,$b);
// ...
}
// ...
}
А затем используйте этот установщик перед другими методами, чтобы дать экземпляр другой модели, чтобы он мог использоваться методами.
$this->load->model('X');
$this->load->model('Y');
$this->X->setY($this->Y);
$this->X->doItRightNow($something,$somethingElse);
2) Иметь параметр в методе, по которому я передам другой экземпляр модели из контроллера.
class X extends Model {
public function doItRightNow($a,$b,$Y_model) {
$list = $Y_model->getSomeList($a,$b);
// ...
}
// ...
}
И используйте это так:
$this->load->model('X');
$this->load->model('Y');
$this->X->doItRightNow($something,$somethingElse,$this->Y);
Я думаю, что это более чистые возможности.
Какой способ использования зависит от того, сколько методов необходимо для доступа к другой модели. Если есть один или два, было бы лучше дать это как параметр метода. Если больше - я думаю, что лучше иметь атрибут класса и сеттер.
И элегантным образом вы можете указать ту или иную модель в зависимости от какого-либо условия - если они оба частично реализуют один и тот же интерфейс с возвращаемыми данными одного и того же типа (это редко полезно, но иногда бывает).
Я думаю, что обычно лучше писать библиотеки, которые обращаются к моделям, а затем включают библиотеки в вашу модель, если это необходимо.
Например, если вам нужно было проверить, уполномочен ли кто-либо выполнить определенное действие CRUD, вы можете включить любую используемую вами библиотеку аутентификации (в большинстве случаев она, вероятно, включается автоматически). Вы не обязательно хотели бы получить доступ к модели напрямую - она просто кажется грязной и неправильной.
Я думаю, что предпочтительный способ - сделать то, что вам нужно сделать в вашем контроллере, и передать результаты метода (ов) одной модели, если необходимо, в метод (ы) другой модели.
Несмотря на это, я не понимаю, почему было бы невозможно включить одну модель в другую, по сути. Я не думаю, что вы можете сделать это с синтаксисом, который вы показываете, хотя. Вы должны сделать это каким-то другим запутанным способом. В любом случае, IMO, это плохая практика - включать модель непосредственно в другую модель.
В CI 2.0 вы можете просто вызывать одну модель напрямую из другой.
Лучше создать вспомогательную функцию, а не вызывать ее из другой модели, чтобы ее можно было использовать одновременно в двух моделях и повторно использовать код.