Доступ к моделям 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, это плохая идея. Попробуйте переосмыслить свой макет и просто передать данные в / из контроллера на модели.

http://codeigniter.com/forums/viewthread/69833/

Вы можете загружать модели из моделей, как говорит Фил Стерджон, но вы должны быть осторожны с зависимостями, если загружаете модели в конструктор моделей: если модель 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 вы можете просто вызывать одну модель напрямую из другой.

Лучше создать вспомогательную функцию, а не вызывать ее из другой модели, чтобы ее можно было использовать одновременно в двух моделях и повторно использовать код.

Другие вопросы по тегам