Модели Codeigniter, загруженные в контроллер, перезаписываются моделями, загруженными в модели - PullRequest
1 голос
/ 14 ноября 2011

У меня путаница в области видимости объекта Codeigniter.

Допустим, я загружаю модель в контроллер:

$this->load->model('A');
$this->A->loadUser(123); // loads user with ID 123
// output of $this->A now shows user 123

$this->load->model('B');
$this->B->examineUser ();
// output of $this->A now shows user 345

class B extends Model
{
    public function examineUser ()
    {
        $this->load->model('A');
        $this->A->loadUser(345); // loads user with ID 345
    }
}

Я бы подумал, что $ this-> A будет отличаться от $ this-> B-> A, но это не так. Как лучше всего решить эту проблему? Похоже, что -> load-> model ('A') в методе examUser () ничего не делает, потому что он был загружен в контроллер. Затем вызов loadUser () внутри этого метода перезаписывает сохраненные свойства $ this-> A. Это похоже на багфест, ожидающий случиться. Если бы мне нужны были глобальные модели, я бы использовал статические классы. То, что я хотел, - это что-то локально привязанное к объекту модели, в котором я находился.

Есть ли способ, которым я могу достичь этого, но не выходить за рамки обычного способа работы CI?

Followup / связанные: Где большинство людей помещают туда вызовы "-> load-> model"? Все в начале действия контроллера? Я подумал, что было бы проще - хотя, возможно, и не отличным программированием с точки зрения внедрения зависимостей - загрузить их в саму модель (конструкцию или каждый метод).

Ответы [ 3 ]

1 голос
/ 14 ноября 2011

К сожалению, загрузчик работает не так. CodeIgniter реализует одноэлементный шаблон, который проверит, включен ли класс, создан ли его экземпляр и установлен ли он в $ this-> A, а затем будет проигнорирован при повторной загрузке. Даже если вы находитесь внутри модели, $ this-> A будет ссылаться на суперэкземпляр с помощью __get () в классе Model. Алис, или просто сделай:

class B extends Model
{
    public function examineUser ()
    {
        $user = new A;
        $user->loadUser(345); // loads user with ID 345
    }
}
1 голос
/ 14 ноября 2011

Каждый раз, когда вы используете класс загрузчика ($this->load->), он загружает объект в основной объект CI.Объект CI - это тот, который вы продолжаете называть $this->.Что вы сделали, так это дважды загрузили модель A в объект CI.

По сути, все объекты, загруженные с использованием класса Loader, попадают в одну глобальную область видимости.Если вам нужны два одинаковых типа, присвойте им разные имена, как указано в $this->load->model('A','C').Я не знаю, как обойти это, если вы не вернетесь к использованию стандартного болотного PHP.

В коде моей команды мы обычно загружаем модели в конструктор контроллера, затем загружаем данные для отправки в представлениев функции часто _remap().

0 голосов
/ 14 ноября 2011

Вот что я решил сделать, пожалуйста, прокомментируйте, если у вас есть совет:

Я расширил класс загрузчика CI:

<?php

class SSR_Loader extends CI_Loader
{
    function __construct()
    {  
        parent::__construct ();
    }  

/**
 * Model Retriever
 *
 * Written by handerson@executiveboard.com to create and return a model instead of putting it into global $this
 *
 * Based on original 2.0.2 CI_Loader::model ()
 *
 */
    function get_model($model)
    {  
        if (empty ($model))
        {  
            return;
        }  

        $name = basename ($model);

        if (!in_array($name, $this->_ci_models, TRUE))
        {  
            $this->model ($model);  
        }  

        $name = ucfirst($name);
        return new $name ();
    }  
}

Видят ли какие-либо гуру CI проблемус этим, прежде чем я потрачу немного времени на изменение своего кода, чтобы принять возвращаемый объект, ала:

// in a controller:
public function test ($user_id=null)
{
    $this->_logged_in_user = $this->load->get_model ('/db/users');
    $this->_viewed_user    = $this->load->get_model ('/db/users');

    $this->_logged_in_user->load($this->session->userdata ('user.id'));
    $this->_viewed_user->load($user_id);
}

Я мог бы также сделать private $_logged_in_user, чтобы сделать его доступным в контроллере, но принудительно ограничить егопросто текущий контроллер и ни разу не пролить, или я мог бы просто сделать $_logged_in_user = $this->load->get_model ('/db/users'); и ограничить его только текущим методом, что, вероятно, я буду делать чаще.

Это выглядит как довольнопростой способ «исправить» эту проблему (я говорю «исправить», потому что это на самом деле не ошибка, а просто способ делать то, что я считаю плохой идеей).Кто-нибудь видит какие-либо недостатки?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...