Передача данных из MVC-контроллера для просмотра в PHP

У меня есть собственный фреймворк PHP MVC, созданный вручную для некоторых проектов, над которыми я работаю. Когда я впервые создал фреймворк, это было в контексте создания административной CMS. Таким образом, между моделью, представлением и контроллером существует очень хорошая однозначная связь. У вас есть одна строка в базе данных, которая соответствует одной модели. Контроллер загружает модель и передает ее в представление для визуализации (например, в форму редактирования). Красиво, чисто и легко.

Однако теперь, когда я работаю над интерфейсом сайта, все становится не так актуально. Страница не всегда является видом одной модели. Это может быть список каталогов пользователей с 20 пользователями (каждая модель User). Кроме того, могут быть метаданные о запросе, такие как разбивка на страницы (текущая страница, общее количество страниц, количество результатов) и / или поисковый запрос.

Мой вопрос: как лучше всего передать все эти данные в представление?

Некоторые варианты я рассматриваю:

  • Попросите контроллер создать массив и передать его представлению как один параметр:

    class UserController{
    
        public function renderView(){
    
            // assume there's some logic to create models, get pagination, etc.
            $data = array()
            $data['models'] = $models; 
            $data['currentPage'] = $current;
            $data['totalPages'] = $total;
            return $view->render($data);
        }
    }
    
    class UserView{
        public function render($data){
            // render the data
        }
    }
    
  • Создайте свойства в классе представления и попросите контроллер заполнить их:

    class UserView{
        public $models;
        public $currentPage;
        public $totalPages;
    }
    
    class UserController{
    
        public function renderView(){
    
            // assume there's some logic to create models, get pagination, etc.
            $view = new UserView();
            $view->models = $models; 
            $view->currentPage = $current;
            $view->totalPages = $total;
            return $view->render();
        }
    }
    
  • Предоставьте представлению какой-то общий объект HashMap или Collection в качестве контейнера, который может содержать любое произвольное количество и имя данных.

    class UserView{
        public $collection = new Collection(); // works like a Java collection
    }
    
    class UserController{
    
        public function renderView(){
    
            // assume there's some logic to create models, get pagination, etc. 
            $view = new UserView();
            $view->collection->add($models,'models');
            $view->collection->add($currentPage,'currentPage');        
            return $view->render();
        }
    }
    

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


person Warren Benedetto    schedule 04.06.2009    source источник


Ответы (3)


Я собираюсь порекомендовать концепцию толстых моделей, тонких контроллеров (или, тонкие контроллеры Fat Models, если вы предпочитаете ...)

Другими словами, ваша модель слишком строгая - привязка вашей модели к представлению только чего-то вроде RowDataGateway чрезвычайно ограничивает.

На самом деле, я думаю, что хорошие модели скрывают тот факт, что вы вообще читаете данные из базы данных. Потому что на самом деле ваши данные могут быть в текстовых файлах или из веб-службы, или что-то еще. Если вы относитесь к своей модели как к прославленному DBAL, вы обрекаете себя на наличие тесно связанного кода в ваших контроллерах, который просто не позволит вам отойти от образа мышления «данные поступают только из базы данных».

person Peter Bailey    schedule 04.06.2009
comment
Забавно, я только что прочитал статью Джеймиса Бака о Fat Models перед тем, как опубликовать этот вопрос, но я не понимал, что поиск в Google концепции вернет такое количество ресурсов по этой концепции. Я думал, что это просто его собственная маленькая философия. Спасибо за совет. - person Warren Benedetto; 04.06.2009
comment
Хорошая статья :-) Я не уверен, что полностью согласен с идеей Fat Models. Я думаю, что модель должна быть ТОЛЬКО моделью с методами, которые действуют на себя (в единственном числе). Другими словами, такой метод, как FindPeople (), не подошел бы. Однако я полностью согласен с преимуществами тонкого контроллера. Введите аргумент для уровня обслуживания. Я мало что знаю об этом и не претендую на звание эксперта, но я думаю, что на это стоит указать. Да, это добавило бы дополнительной сложности новому слою, но контроллер мог бы вызывать, например, PeopleService :: FindPeople () - person Dave Archer; 04.06.2009
comment
Сама модель может быть многослойной. Некоторые готовые фреймворки уже содержат многоуровневую модель. Symfony, например, поставляется как с DBAL, так и с ORM, которые он поддерживает с продвижением задач. ZF предоставляет нам шлюзы таблиц и строк и оставляет нам право применять модель предметной области. Я бы рекомендовал прочитать статью Билла Карвина здесь karwin.blogspot.com /2008/05/activerecord-does-not-suck.html - кстати, он тоже заядлый SOer. - person Peter Bailey; 04.06.2009
comment
Это хороший совет, если толстая модель относится к слою кода, а не к объекту или классу. Слишком многие забывают, что MVC представляет три разных уровня приложения, а не обязательно три разных типа объектов. - person Cypher; 24.03.2014

Я видел оба первых метода, реализованные в популярных фреймворках MVC / шаблонов.

django использует первый метод, передавая представлению словарь переменных, которые оно использует для заполнения шаблона.

smarty использует второй метод, создавая объект Smarty и присваивая значения каждому свойству в контейнере.

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

На самом деле, полагаю, я не сказал того, о чем вы еще не подумали. По сути, это все звуковые идеи, поэтому воплощайте в жизнь то, что вам удобнее всего.

person Marquis Wang    schedule 04.06.2009

В том, который я использую, он автоматически имеет свойство представления в контроллере, с помощью которого вы можете получить доступ к методам и свойствам представления. После этого все общедоступные свойства становятся доступными в представлении "$ this", поскольку представление отображается в контексте собственных объектов.

В контроллере:

$this->view->myVar = 'test';

И в представлении:

$this->myVar; // 'test'

То же самое касается макета, поскольку оба являются отдельными экземплярами одного и того же объекта представления:

$this->layout->myVar = 'test';

А потом в макете:

$this->myVar; // 'test'

Раньше фреймворк был проприетарным, но скоро будет выпущен для широкой публики. Я был бы счастлив прислать вам код оттуда, если вы думаете, что это поможет. Помните, что самый простой ответ - обычно лучший ответ.

person Tres    schedule 04.06.2009
comment
Это именно то, что я думаю во втором примере. Я оставил пример кода простым, поэтому я не учел тот факт, что у моего контроллера действительно есть экземпляр представления, и поэтому он будет работать именно так, как вы предлагаете: $ this- ›view-› foo = 'bar' Что меня неудобно об этом варианте заключается в том, что у меня есть один класс View, который может отображать 5 разных представлений одной и той же модели. Каждое представление может иметь свои собственные требования к данным. Это означает, что класс View будет иметь набор свойств, лишь некоторые из которых будут иметь отношение к какому-либо одному представлению. Это менее чисто, чем хотелось бы. Какие-либо предложения? - person Warren Benedetto; 04.06.2009
comment
В моем примере выше я заметил, что макет и представление - это отдельные экземпляры. Вместо того, чтобы делать ваше представление одноэлементным, вы можете захотеть сделать его так, чтобы вы могли создавать несколько объектов представления. Таким образом, представление является экземпляром, отличным от макета, и свойства, которые вы устанавливаете для каждого, не зависят друг от друга. Поскольку у вас может быть несколько экземпляров, у вас также могут быть разные вспомогательные пути, пути просмотра и т. Д., Поэтому некоторые помощники доступны только для определенных представлений, как и свойства. Это обеспечивает более высокий уровень настройки, если когда-либо понадобится, а также логическую организацию. - person Tres; 09.06.2009