Страницы

Поиск по вопросам

Показаны сообщения с ярлыком mvc. Показать все сообщения
Показаны сообщения с ярлыком mvc. Показать все сообщения

вторник, 7 апреля 2020 г.

как правильно организовать MVC модель?

#qt #mvc

                    
Пишу учебное задание, пытаюсь написать некоторое подобие MVC. Пытаюсь разделить логику
программы и интерфейса в разные классы. Соответственно, запилил классы Controller и
View. View содержит нажатия всяких кнопок, считывание с полей, обновление содержимого
меток и т.п. Controller же должен по идее инициировать запуск View и считывать получаемые
значения для проведения операций над ними и передачи этого добра в модель. Я сделал
вьюху элементом контроллера, вызываю её, но столкнулся с проблемой - а как, собственно
получать из вьюхи данные? Т.е. например, я понимаю, что можно запустить view->show()
и прочие методы вызывать из контроллера, но как обеспечить свободную работу с формой
пользователю и при этом вовремя получать информацию о его действиях?
    


Ответы

Ответ 1



Так у вас слоты вьюхи и так срабатывают по событиям пользователя. И в этих слотах должны вызываться методы контроллера. А вот как раз в контроллере не должно быть вызовов методов вьюхи, иначе они получаются привязаны сильно. По событиям контроллера (по его сигналам) так же должна обновляться view.

вторник, 17 марта 2020 г.

ASP.NET MVC или Python Django

#c_sharp #aspnet #mvc #python #django


Добрый вечер. Я собираюсь создать веб приложение с повышенной нагрузкой. И сейчас
у меня стоит выбор инструмента, но определиться я не как не могу. Обе технологии я
знаю на должном уровне, и обе отлично подходят под мою задачу. Скрипт приложения будет
стоять на разных сайтах, получая код из моего скрипта из бд. В качестве базы данных
я буду использовать Postgresql(даже в случае ASP.NET), так как Sql server по началу
в финансах не потяну (но хотелось бы и по этому поводу что-нибудь услышать). В качестве
серверной ОС скорее всего будет использоваться Windows Server 2008 R2(даже в случае
с Python Django), возможно и линукс подобные, пока не решил точно. Подскажите пожалуйста
плюсы и минусы. Спасибо.     


Ответы

Ответ 1



Есть несколько "сравнений", типа этого: http://www.pythondiary.com/blog/Apr.11,2012/comparing-django-aspnet-mvc.html, но конкретики в них мало, да и сравнивать совершенно разные платформы сложно. Точно можно сказать, что windows выйдет дороже. Дороже лицензия, дороже саппорт (Вы же не собираетесь нагруженный проект поддерживать сами вручную?). Абсолютно точно деплой python на винде будет неудобным и глючным (а деплоя asp на линуксе вообще не будет). В остальном - берите то, что лучше знаете, что больше нравится, и для чего лучше представляете себе могущие возникнуть сложности. Хуже нет на большом проекте, чем упереться в неочевидный косяк технологии, которая выбрана маркетологами из-за "низкого ТСО".

Ответ 2



Предложение: python + django (вместе с gunicorn), ngnix, postgresql. ОС - можно хоть убунту взять на первом этапе (несложная настройка). Если опишете задачу подробнее - можно порекомендовать какие-нибудь NoSQL БД (как правило, под конкретную задачу можно выбрать удачное решение).

Ответ 3



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

понедельник, 9 марта 2020 г.

В чем преимущества выделения контроллера в mvc?

#java #mvc #шаблоны_проектирования


У меня сразу несколько вопросов по mvc. Спрашивать буду на примере игрушечной программки,
которую специально для этого написал:

public class View implements Observer {

private Model model;
private IController controller;

private JLabel firstNumber = new JLabel();
private JLabel secondNumber = new JLabel();
private JLabel resultLabel = new JLabel();

public static void main(String[] args) {
    SwingUtilities.invokeLater(new Runnable() {
        @Override
        public void run() {
            Model model = new Model();
            IController controller = new Controller();
            View view = new View();
            view.setModel(model);
            view.setController(controller);
            view.createAndShowGUI();
        }
    });
}

public void setModel(Model model) {
    this.model = model;
    model.addObserver(this);
}

public void setController(IController controller) {
    this.controller = controller;
}

public void createAndShowGUI() {
    JFrame frame = new JFrame("mvc train");
    frame.setSize(400, 400);
    frame.getContentPane().add(createMainPanel());
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.setVisible(true);
}

private Component createMainPanel() {
    JPanel mainPanel = new JPanel();
    mainPanel.add(firstNumber);
    mainPanel.add(secondNumber);
    mainPanel.add(resultLabel);
    JButton inc1 = new JButton("increment first");
    inc1.addActionListener(new ActionListener() {

        @Override
        public void actionPerformed(ActionEvent e) {
            controller.execute("inc1", model);
        }
    });
    JButton dec1 = new JButton("decrement first");
    dec1.addActionListener(new ActionListener() {

        @Override
        public void actionPerformed(ActionEvent e) {
            controller.execute("dec1", model);
        }
    });
    mainPanel.add(inc1);
    mainPanel.add(dec1);
    JButton inc2 = new JButton("increment second");
    inc2.addActionListener(new ActionListener() {

        @Override
        public void actionPerformed(ActionEvent e) {
            controller.execute("inc2", model);
        }
    });
    JButton dec2 = new JButton("decrement second");
    dec2.addActionListener(new ActionListener() {

        @Override
        public void actionPerformed(ActionEvent e) {
            controller.execute("dec2", model);
        }
    });
    mainPanel.add(inc2);
    mainPanel.add(dec2);
    return mainPanel;
}

@Override
public void update(Observable arg0, Object arg1) {
    firstNumber.setText("" + model.getA());
    secondNumber.setText("" + model.getB());
    resultLabel.setText("" + (model.getA() + model.getB()));
}

}


Это класс представления. Получается такая картинка:


Кнопка increment first увеличивает на единицу первое число, increment second - второе,
decrement first уменьшает первое число на единицу, decrement secomd - второе. В общем,
после двух нажатий на increment first и одного нажатия на increment second получаем
такую картинку:



Два числа хранятся в модели. Вот она:

public class Model extends Observable {

private int a;
private int b;

public void incrementA() {
    a++;
    setChanged();
    notifyObservers();
}

public void incrementB() {
    b++;
    setChanged();
    notifyObservers();
}

public void decrementA() {
    a--;
    setChanged();
    notifyObservers();
}

public void decrementB() {
    b--;
    setChanged();
    notifyObservers();
}

public int getA() {
    return a;
}

public int getB() {
    return b;
}

@Override
public void addObserver(Observer observer) {
    super.addObserver(observer);
    setChanged();
    notifyObservers();
}

}


Мой контроллер:

public class Controller implements IController {

@Override
public void execute(String action, Model model) {
    switch (action) {
    case "inc1":
        model.incrementA();
        break;
    case "inc2":
        model.incrementB();
        break;
    case "dec1":
        model.decrementA();
        break;
    case "dec2":
        model.decrementB();
    }
}

}


Теперь вопросы.
Самый главный вопрос собственно в названии.


Чем нам помог контроллер? Код из веток case оператора switch в
контроллере мог бы с таким же успехом находится в слушателях. На
каждую ветку по слушателю. В итоге слушателей все равно приходится
создавать, что бы вызвать метод контроллера. А потом в этом методе в
операторе switch прописывать тот же самой код, что мог бы быть в
слушателях. Может быть я вообще неправильно реализовал mvc?
Подозреваю что именно так. Причем именно в части контроллера. Потому
что по нему в сети мало информации. Если это так то прошу подсказать
как правильно. Слышал что можно создавать контроллеры для каждого
элемента (в данном случае для каждой кнопки). Но ситуация не сильно
поменяется.
В моем примере все методы, которые вызывается в ветках case не имеют параметров.
В реальных программах это скорее всего будет не так. Некоторые кнопки могли бы требовать
вызовов методов с параметрами, причем с разным количеством параметров. Что делать в
такой ситуации?
Где лучше вычислять самое правое число? В моем примере я делаю это в функции update().
Не лучше ли это делать в модели?

    


Ответы

Ответ 1



Контроллер помогает структурировать код. Весь код, реагирующий на пользовательский ввод, принадлежит контроллеру. Можно было бы всё слить в один класс, и делать всю логику в OnClick, и код получился бы наверное даже короче. Но вашей целью должен быть не самый короткий, а самый понятный и легко поддерживаемый код. Мне кажется, ваша диспетчеризация команд по строкам — неправильна. Команды должны быть не строками, а объектами. (У нас же ООП, в конце-концов, да?) И вместо длинного свитча у вас должен быть всего лишь вызов Invoke. [Но это практика из MVVM, общепринятого паттерна в WPF, а традиции в MVC могут быть и другими.] Вычисления принадлежат модели и только ей. Представление должно не выполнять работу модели (а сложение в реальной программе превратится в серьёзное, длинное вычисление), а лишь только отображать её.

вторник, 25 февраля 2020 г.

Структура папок сайта. Как грамотней?

#mvc #веб_программирование


В общем, планируется несложный сайт-визитка с небольшим количеством PHP, для вывода
из базы данных товаров. Встал такой вопрос - как грамотно организовать структуру папок
сайта, что к чему подключать и как разделять код? Можно коротко, думаю, я пойму общую
идею. Пока что есть такой вариант:

/css
/js
/images
/includes
index.php
page1.php
page2.php
page3.php


PHP-файлы просто связаны между собой ссылками (в меню сайта), в нужные места этих
файлов подключаются файлы из папки includes, которые выводят какие-то данные из базы.
Как вариант - создать папку template для шаблонов, тогда туда буду передаваться данные
из файлов папки includes и уже в главные файлы будут делаться не php-вставки, а вставляться
шаблоны. То есть, получается, что index.php, page1.php, page2.php, page3.php это просто
файлы с html-разметкой и php-вставками (или шаблонами). Есть еще какие-то, более грамотные
варианты разделения?
    


Ответы

Ответ 1



В идеале любой сайт должен иметь такую структуру: app (корневая папка) --core --components --models --other code-related stuff --templates --public - именно эта папка смотрит "наружу" ----assets ----images ----js ----css ----index.php --logs Здесь главное - не названия папок, а то, что наружу смотрит всего одна папка и один исполняемый файл, в результате сайт у вас оказывается наименее уязвимым. И не забывайте применять intval() и подобные операции к приходящим айдишникам. update: Еще одна вещь, которую необходимо отметить - если заливаются какие-то файлы, то надо их хранить вне публичной директории, либо (если, например, это пользовательские изображения, которые должны показываться) фильтровать их по расширению и быть уверенным, что сервер не может исполнять файлы с таким расширением. Буквально на этой неделе сталкивался с тем, что так сломали самопис (а в свое время так уронили тысячи сайтов на вордпрессе).

Как контроллеры MVC вызывают несколько разных сущностей (компонентов, элементов, модулей)?

#веб_программирование #mvc #проектирование #php


Не первый год программирую, но не могу понять одну простую вещь: как контроллеры
MVC формируют многофункциональные страницы. Например, на странице на этом сайте есть
верхний тулбар, меню справа, меню футреа, основной контент и т.д.
Мне гораздо легче дается понимание HMVC, то есть компонентного подхода. Там все просто:
в шаблоне вызываем нужный компонент, и он уже работает как замкнутая система со своим
внутренним MVC.
Буду признателен, если кто-то сможет втолковать идею. Сколько статей не прочитал,
так и не понял этого.    


Ответы

Ответ 1



Класическое mvc это когда представление по событию модели берет из неё положенное интерфейсом, диспатчит контроллеру, а контроллер меняет модель. Стоит заострить внимание, что контроллер не меняет представление вообще ( хотя в классике это ДОПУСКАЕТСЯ ), а модель меняет так, что решение меняться или нет остается за моделью. И такая модель называется "активной" и при ней контроллер "тонким", что является единственно верным вариантом. ВСЁ! Остальное это неправильно и ложно. Но чья-то глупость распространилась так, что даже гуру не верят в первоисточник, хотя wiki и "gof" об это говорят прямо (и причиной такой mvc-ериси, как я считаю, стало опускание из контекста статьи контроллера). Обновление Контроллер служит связующим звеном между представлением и модель. Но дело в том, что в wiki и всяких статейках приводятся (если и правильные реализации) минимальные примеры, которые в жизни не существуют. И ещё уясните одну маленькую и ускользающую от всех деталь - представление не имеет ссылку на модель, представление имеет ссылку на реализацию интерфейса. То есть, по ооп, структура строится на интерфейсах, модель это абстракция, а не живой объект. И когда все слюнями плюются и говорят, что представление имея ссылку на модель, нарушает концепцию о разделении логики от отображения, то просто говорящие не углублялись в mvc сильно, а используют навязываемые фраймворки, которые делают люди, но их концепцию обожествляют и выставляют эталоном.

Ответ 2



MVC была разработана в 1979 году, когда дела шли немного по-другому (меня тогда еще не было на этом свете, но, подозреваю, каждое окно ограничивалось ровно одной функцией), и предназначалась она не для веба. MVC используют просто потому, что она позволяет избавиться от загаживания кода, следуя простому паттерну, и многие вещи делаются в обход парадигмы, например, каждый виджет (например, меню страниц) должен был бы получить данные от контроллера, но наверняка подтягивает их сам из модели. Скажем так, это нестрогое MVC. HMVC и мне импонирует больше MVC. "предназначалась она не для веба" = не то чтобы она плохо подходит вебу, просто когда концепция была озвучена, никто и не думал, подойдет ли это для php-фреймворка.

Ответ 3



Ну, насколько я понимаю: при заходе на страничку контроллер получает набор инструкций, (вывести меню, вывести контент и т.д.), он посылает эти инструкции по своим модулям, те, в свою очередь, обрабатывают инстукции, из вьювок берут инфу о том, КАК нужно вывести, и выводят каждый по отдельности. Но чаще всего все пишут так: контроллер получает функции, и контроллер САМ работает с модулями и вьюхами, т.е. модуль выступает в роли класса определенной сущности, где с помощью методов контроллер получает необходимую инфу, сам загружает вьюху и сам их соединяет.

понедельник, 24 февраля 2020 г.

Visual Studio меняет поток при отладке и теряются данные

#c_sharp #visual_studio #mvc #отладка


Пишу на mvc3. Передаю данные из представления в контроллер (используя форму, методом
POST). В контроллере стоит у меня точка останова. Когда я нажимаю на кнопку "След.
шаг"(при отладке) он переходит к следующему шагу но потом сразу перескакивает обратно.
Приходится нажимать на кнопку два раза, что бы VS выполнил одну операцию. Текст который
выдает при этом VS на скринах.



    


Ответы

Ответ 1



Visual Studio отлаживает приложение целиком. Если вам в приложение пришло два запроса - они будут выполняться в двух разных потоках. Оба потока попадут на ваш breakpoint. И студия будет прыгать между ними при отладке туда-сюда. Хотите удобной пошаговой отладки - сделайте так, чтобы приходил ровно один поток (например, запишите запрос fiddler-ом, и проигрывайте его). Или, если совсем не получается избежать двух запросов, поставьте на паузу все остальные потоки в Debug / Window / Threads.

четверг, 13 февраля 2020 г.

Структура asp.net mvc приложения

#aspnet #aspnet_mvc #mvc


Здравствуйте. Недавно меня заинтересовало, как красиво преобразовывать данные для
передачи в вид и вообще, как грамотно делать приложения на asp.net mvc. Здесь мне ответили. 
Я честно говоря не слишком понимаю эти термины пока не увижу код воочию.
Если кто-то программирует использую такой подход, то выложите здесь примеры или киньте
в скайпе: umnick.jo. Буду рад любой помощи. Спасибо    


Ответы

Ответ 1



В проекте должны быть 2 независимых модели данных: доменная модель и "вью модель". Чтобы преобразовать сущности доменной модели в сущности вью модели (или наоборот) для дальнейшего отображения во вьюхах удобно использовать AutoMapper или любой другой аналог. Пример: Этап конфигурации: Mapper.CreateMap() .ForMember(m => m.IsContainUsers, a => a.MapFrom(p => p.Subjects.Count > 0)); Обычно обе модели во многом совпадают (одинаковые свойства) и в подобном случае конфигурация будет состоять из одной строки создания "мапа", либо как в примере у вью-модели есть дополнительное свойство IsContainUsers, которое и сконфигурировано. Этап преобразования: var domainWatchList = GetFromDatabase(); var viewWatchList = Mapper.Map(domainWatchList);

Как настроить приложение MVC для работы через HTTPS соединение?

#c_sharp #aspnet_mvc #mvc #https #config


Доброго времени суток. 

Суть вопроса изложена в заголовке. Нужно ли вручную создавать сертификат и подкручивать
его к IIS? Или достаточно просто прописать что-то в файле Web.config??? Или нужно перед
каждым методом всех контроллеров указывать [RequireHttps]??? Если есть нормальная документация,
ткните носом, пожалуйста, потому что я ничего особо дельного не нашла...
    


Ответы

Ответ 1



Да, сертификат нужно подкрутить в IIS, инструкция и бесплатный сертфикат на год могут быть найдены, например, тут. Также, в IIS для работы по HTTPS MVC сайта требуется правильно указать биндинг к https: Если вы не собираетесь использовать для сайта защищённый и обычный HTTP одновременно, то никаких атрибутов указывать не требуется, как и править Web.config - IIS не будет отзываться на обычные HTTP запросы.

Ответ 2



Если создать сертификат для сервера самостоятельно (self signed certificate), то многие браузеры будут выдавать пользователю предупреждающее сообщение. Чтобы такого предупреждения не было, нужно заказать/купить SSL-сертификат у подтвержденных центров сертификации. Сделать это можно, например, у регистраторов доменов или хостинг провайдеров. Как настроить ssl-сертификат в IIS можно посмотреть тут. Как сделать ssl-сертификат самому в IIS тут. Веб-приложение будет работать без каких-либо правок в web.config. Атрибут RequireHttps требует вызывать отмеченный методы (Action) по HTTPS.

воскресенье, 9 февраля 2020 г.

Нужно ли создавать отдельные классы для сущностей бд и rest запросов?

#база_данных #mvc #rest #best_practice


У меня есть контроллер, который принимает или возвращает объект юзера. Так же у меня
есть база данных, которая хранит юзера. Естественно, что не все поля объекта, которые
хранит бд должны отправляться сервером. Нужно ли создавать отдельные класс для сущности
бд, класс, который будет отправлен сервером, и класс, который будет выполнять бизнесс-логику
или можно просто создать 1 класс и уже перед отправкой решать какие поля добавлять
в JSON, а какие игнорировать?
    


Ответы

Ответ 1



Все зависит от тяжести случая. Представьте, у вас таблица с юзером одна, а форм где показывается пользовательсная информация две. А потом Вы захотите добавить третью, не задев первые две. В случае с отдельными классами на каждую форму(запрос), Вы добавите новый класс и новую форму, а в случае с одним классом Вам придется лезть в уже рабочий(протестированный) код, менять юнит тесты. А еще это можете быть не Вы сейчас, а Вы через 3 года, или Ваш коллега. С другой стороны, если приложение одноразовое, то игра не стоит свеч.

Ответ 2



Если Вы планируете следовать паттерну MVC и при этом хотите исключить какие-то данные из сущности перед отправкой клиенту, то лучше создать для этого отдельный класс и отправлять его вместо оригинальной модели. Создание и заполнение данными экземпляра этого класса можно выполнить в контроллере или, как вариант в оригинальной модели через соответствующий метод.

пятница, 7 февраля 2020 г.

Qt Баг с точностью после запятой в таблицах

#cpp #qt #mvc #tableview


Привет Всем, столкнулся с такой проблемой, во всех таблицах, базовых примерах да
и вообще Qt почему то допускает писать в таблицах значения только с точностью два знака
после запятой, не более. 
Как пример возьмем стандартный пример в Qt sqlbrowser.
Запускаем пример, заходим, видим в дереве 2 элемента Movies и Names, заходим в Movies,
далее в колонке Rating видим значения:
Например: 8,1
Нужно: 8,0001  , но больше двух цифр не вбивается после запятой, так во всех примерах QT.
Вопрос как данную проблему исправить, основываясь на этом примере?
Желательно привести данный участок кода, который разрешит эту проблему.
    


Ответы

Ответ 1



Это не баг, а просто соглашение, принятое в Qt по умолчанию для чисел с плавающей точкой. В одной задаче нужно показывать один знак после запятой, в другой все девяносто девять. Если не подходит количество, принятое по умолчанию, то создают собственный делегат - виджет, который предоставляет пользователю не только альтернативный вид данных в таблице, но и их редактирование. Файл delegate.h: #ifndef DELEGATE_H #define DELEGATE_H #include class Delegate : public QStyledItemDelegate { Q_OBJECT public: Delegate(QObject *parent = Q_NULLPTR); virtual QString displayText(const QVariant &value , const QLocale &locale) const; virtual QWidget *createEditor(QWidget *parent , const QStyleOptionViewItem &option , const QModelIndex &index) const; virtual void setEditorData(QWidget *editor , const QModelIndex &index) const; virtual void setModelData(QWidget *editor , QAbstractItemModel *model , const QModelIndex &index) const; }; #endif Файл delegate.cpp: #include "delegate.h" #include Delegate::Delegate(QObject *parent) : QStyledItemDelegate(parent) {} QString Delegate::displayText(const QVariant &value , const QLocale &locale) const { Q_UNUSED(locale); // Шесть знаков после запятой. return QString::number(value.toDouble(), 'f', 6); // Если нет необходимости в том, чтобы поле таблицы // содержало заканчивающие числа нули, то вместо // аргумента `f` нужно указать значение `g`. // return QString::number(value.toDouble(), 'g', 6); } QWidget *Delegate::createEditor(QWidget *parent , const QStyleOptionViewItem &option , const QModelIndex &index) const { Q_UNUSED(option); Q_UNUSED(index); QDoubleSpinBox *editor = new QDoubleSpinBox(parent); // Шесть знаков после запятой. editor->setDecimals(6); return editor; } void Delegate::setEditorData(QWidget *editor , const QModelIndex &index) const { QDoubleSpinBox *sbox = qobject_cast(editor); if(sbox != Q_NULLPTR) { sbox->setValue(index.model() ->data(index, Qt::EditRole).toDouble()); } } void Delegate::setModelData(QWidget *editor , QAbstractItemModel *model , const QModelIndex &index) const { QDoubleSpinBox *sbox = qobject_cast(editor); if(sbox != Q_NULLPTR) { model->setData(index, sbox->value(), Qt::EditRole); } } В методе Delegate::createEditor() строка editor->setDecimals(6) установит для делегата шесть знаков после запятой. Установка делегата в виджет таблицы: QTableView *view = new QTableView(); view->setModel(model); view->setItemDelegate(new Delegate(view));

среда, 29 января 2020 г.

Информация по MVC

#mvc


Уже не первый раз встречаюсь с MVC в статьях. Очень интересно было бы узнать побольше
об этом. Найти достаточно адекватный источник пока не удалось. Практически каждая статья
пытается толковать об этом по своему. Поэтому хочется увидеть названия адекватных книг,
ссылки на статьи, возможно хорошее разъяснение темы.    


Ответы

Ответ 1



Фаулер: GUI Architectures Переводы: Часть 1 Часть 2

Ответ 2



Developing a Spring Framework MVC application step-by-step.

Ответ 3



А я б посоветовал взять фреймворк, например, kohana, codeigneter, zend и т.д., короче, любой посовременнее и изучить на его примере и MVC и HMVC :)

Ответ 4



Можете глянуть тут, неплохо написано: http://irbis-team.com/15/3/1

Ответ 5



PureMVC дает возможность попробовать MVC на практике. Библиотека написана на многих языках программирования и широко используется. Имеется подробная документация (в т.ч. и на русском)

Ответ 6



Вот на примере symfony.

воскресенье, 26 января 2020 г.

MVC в PHP на практике

#веб_программирование #mvc #php


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


Контроллер и модель(и). Должен ли соблюдаться принцип - для одного контроллера одна
модель? Например, у меня есть модель page, которая из базы получает данные страницы
(title,scripts,id и т. д.). Как то я могу её использовать для подключения в нестатичных
страницах, там где нужна будет ещё одна модель? Если да, то каким образом это правильно
делать? Унаследовать новую модель из модели page? Или определить в контроллере одну
модель, получить данные, потом так же с другой? Либо есть ещё какой-либо способ, может
быть совсем без модели.


Я так понял, модели и контроллеры должны иметь базовый класс. Что должно быть реализовано
в этих классах? Например стоит ли в базовом классе модели реализовать подключение к базе?


Как лучше сделать подключение к базе? Стоит ли выделить под него отдельный и как
его применять?


Структура приложения. Везде в пример приводят такую структуру: в $_GET принимаются
2 параметра - один идентификатор контроллера, другой - его метод. Так, к примеру работает
YII. Я изменил это так: у каждого контроллера есть один базовый метод, в который передается
аргументом второй параметр, потом сам контроллер решает, что с ним делать. Стоит ли
менять так устоявшуюся структуру?


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


Ответы

Ответ 1



Контроллер и модель(и). Должен ли соблюдаться принцип - для одного контроллера одна модель? Нет, тут пишется как вам угодно, напр. в контроллере Controller_Page можно вызвать модели Model_User, которая возьмет логин текущего пользователя из бд и Model_Article, которая возьмет статью, и все это потом выводится в Вид через этот контроллер. Понимание прийдет к вам с опытом. Я так понял, модели и контроллеры должны иметь базовый класс. Что должно быть реализовано в этих классах? Например стоит ли в базовом классе модели реализовать подключение к базе? В базовых классах лучше указывать какие стили подключаются, заголовки сайта и т.п. а работа с БД это уже как отдельный класс тоже можно реализовать и подключить в базовом. Структура приложения. Везде в пример приводят такую структуру: в $_GET принимаются 2 параметра - один идентификатор контроллера, другой - его метод. Так, к примеру работает YII. Я изменил это так: у каждого контроллера есть один базовый метод, в который передается аргументом второй параметр, потом сам контроллер решает, что с ним делать. Стоит ли менять так устоявшуюся структуру? Во фреймворках реализуется это через $this->request->param('id') или $this->request->post().

Ответ 2



Эти принципы для того, чтобы вам легче было работать. Это просто стиль работы с php. Ну например ты можешь создать один файл и в нем писать и подключение к базам, и внешний вид и контроллер. В классе можно написать функцию которые работают с базой, это еще безопасно, чем писать функции без класса, и можно функций писать статически, чтобы было еще безопасно. Думаю лучше создать отдельный config файл, который подключается с базой, и ее подключить к файлу где класс написать. И вообще мне кажется, что ты сам должен попробовать разные методы, и со временем поймешь, какой подход для тебя еще легче и понятнее. И при этом не забывай про безопасности и про быстроту приложений.

Начинаю разбираться с MVC - какой подход будет правильным?

#php #ооп #mvc


Начну с того, что я новичок, сделал всего один небольшой проектик на php "процедурным"
способом и теперь ищу способ, чтобы перепрыгнуть огромную пропасть, отделяющую процедурное
программирование от ООП. Большая часть инфы по MVC предусматривает, что я уже перебрался
через эту пропасть, и оттого практически бесполезна. Нашёл пока единственную статью,
которая максимально примитивно объясняет, начиная с основ, и пытаюсь по аналогии свой
проектик переделать под MVC.

Возникла проблема - в моём проекте логика чуть посложнее, чем в "сайте-визитке",
и статья не даёт ответа на вопрос, где и как это "посложнее" реализовать.

В упомянутой статье класс View крайне прост: метод View->Generate($view_content,
$view_template) делает require $view_template.'.php', внутри шаблона в свою очередь
в единственном месте стоит require $view_content.'.php'.

У меня, в зависимости от контроллера/метода, необходимо делать вставки в шаблон в
нескольких местах. Вопрос - как реализовать это правильно?

Предполагаемый мной вариант решения: в главный шаблон напихать конструкции вида include
$block[0].'.php' (не require, чтобы не ругался при отсутствии файла), потом этот массив
заполнять именами файлов в соотв. модели...

Сразу возникают вопросы:


если мне в данном view не нужно вставлять скажем $block[0] - как будет выполняться
директива include? Будет ли она пытаться обращаться в файлу (в данном случае NULL)?
Да и вообще, правильно ли так поступать? (upd: вариант конечно if (isset($block[0]))
{ include $block[0].'.php'; } - но это получается часть логики переносится в вид :/ )
как быть с блоками, которые хочется задействовать несколько раз? Например, у меня
там простенькая формочка для фильтрации вывода с базы, но на одной странице она должна
фильтровать поставщиков, а на другой - товар на складе?
Реализовывать формочку через класс?

    


Ответы

Ответ 1



Почитайте что такое виджеты и зачем они. Если вкратце то это независимое обращение к любому модулю вашего сайта, допустим модуль отзывов. Вы вызываете виджет данного модуля, и все инкампсулировано внутри него, он сам определяет на какой он странице (или в параметре передаете), знает к какой модели обратится, и как вывести данные в шаблон. Очень удобны и незаменимы. Издалека ваш подход правильный, но я бы реализовывал массив по типу $content = array( 'header' => 'Hellow world', 'short_description' => 'short description of page', 'footer_links' => array( 0 => array('name' => 'main page', 'link' => 'http://...'), .... ), ); и этот контент передаю непосредственно шаблону, темплейту. Где использую его так:


суббота, 11 января 2020 г.

Как использовать Twig

#php #ооп #mvc #twig


У меня небольшой проект (mvc,OOP). Покажите пожалуйста как правильно подключать Twig
и как его использовать в controller
    


Ответы

Ответ 1



Существует множество способов установки Twig-a. Самый простой и быстрый - это скачивание компонента с GitHub, после чего архив необходимо распаковать, и перекинуть каталог lib в папку с нашим проектом. Ну а теперь давайте приступим к делу и рассмотрим структуру нашего небольшого проекта: compilation_cache lib Twig templates base.html books.html index.php Весь функционал, связанный с подключением и настройкой Twig-а, содержится в файле index.php. В папке templates мы будем хранить файлы шаблонов. В нашем случае, этих файлов 2: base.html с базовым html кодом и books.html с выводом списка книг. В каталоге compilation_cache будут помещаться PHP файлы, созданные Twig-ом для работы. Итак, первое что нам необходимо сделать, так это подключить Twig: require_once 'lib/Twig/Autoloader.php'; Twig_Autoloader::register(); После этого сообщаем шаблонизатору, где у нас хранятся файлы шаблонов. В качестве аргумента передаём путь к каталогу templates: $loader = new Twig_Loader_Filesystem('templates'); Затем создаём объект шаблонизатора и указываем ещё несколько опций: $twig = new Twig_Environment($loader, array( 'cache' => 'compilation_cache', 'auto_reload' => true )); Параметру cache передаём путь к каталогу compilation_cache. Активируем опцию auto_reload, для того чтобы при обновлении страницы Twig заново обрабатывал шаблоны, и мы видели изменения. Если этого не сделать, то шаблонизатор просто закэширует страницы. Когда же работа над проектом будет завершена, эту опцию можно убрать, чтобы ваши страницы закэшировались и грузились ещё быстрее. Для реализации нашего небольшого примера, возьмём список книг и сформируем массив вида ключ - значение: $books = array( array('number' => 'Книга 1', 'title' => 'Гарри Поттер и философский камень', 'date' => '30.06.1997'), array('number' => 'Книга 2', 'title' => 'Гарри Поттер и Тайная комната', 'date' => '2.07.1998'), array('number' => 'Книга 3', 'title' => 'Гарри Поттер и узник Азкабана', 'date' => '8.07.1999'), array('number' => 'Книга 4', 'title' => 'Гарри Поттер и Кубок огня', 'date' => '8.07.2000'), array('number' => 'Книга 5', 'title' => 'Гарри Поттер и Орден Феникса', 'date' => '21.07.2003'), array('number' => 'Книга 6', 'title' => 'Гарри Поттер и Принц-полукровка', 'date' => '16.07.2005'), array('number' => 'Книга 7', 'title' => 'Гарри Поттер и Дары Смерти', 'date' => '21.07.2007') ); Для того чтобы передать данные в какой-то шаблон и вывести html результат, нам необходимо воспользоваться методом render(); В качестве первого аргумента передаём название файла шаблона, который будем выводить. В качестве второго -массив вида ключ - значение. В дальнейшем по заданным ключам мы будем получать доступ к нашим данным в самих шаблонах. echo $twig->render('books.html', array('books' => $books)); Общий вид файла index.php require_once 'lib/Twig/Autoloader.php'; Twig_Autoloader::register(); $loader = new Twig_Loader_Filesystem('templates'); $twig = new Twig_Environment($loader, array( 'cache' => 'compilation_cache', 'auto_reload' => true )); $books = array( array('number' => 'Книга 1', 'title' => 'Гарри Поттер и философский камень', 'date' => '30.06.1997'), array('number' => 'Книга 2', 'title' => 'Гарри Поттер и Тайная комната', 'date' => '2.07.1998'), array('number' => 'Книга 3', 'title' => 'Гарри Поттер и узник Азкабана', 'date' => '8.07.1999'), array('number' => 'Книга 4', 'title' => 'Гарри Поттер и Кубок огня', 'date' => '8.07.2000'), array('number' => 'Книга 5', 'title' => 'Гарри Поттер и Орден Феникса', 'date' => '21.07.2003'), array('number' => 'Книга 6', 'title' => 'Гарри Поттер и Принц-полукровка', 'date' => '16.07.2005'), array('number' => 'Книга 7', 'title' => 'Гарри Поттер и Дары Смерти', 'date' => '21.07.2007') ); echo $twig->render('books.html', array('books' => $books)); Настройка базового шаблона. Базовый шаблон представляет собой обычный html документ со специальными вставками: {% block title %}{% endblock %}
{% block content %} {% endblock %}
В нашем главном шаблоне мы прописываем 2 блока: title и content. Названия блоков выбираем сами. В последствии, в эти общие блоки мы будем внедрять характерную для дочерних страниц информацию. Настройка шаблона вывода книг Для начала в дочернем шаблоне нам необходимо указать шаблон родителя: {% extends "base.html" %} Далее в блок title запишем название дочерней страницы, которая обработается Twig-ом и вставится между тегами title в базовом шаблоне: {% block title %}Серия романов о Гарри Поттере{% endblock %} Затем, пишем содержание, которое внедрится в блок под названием content в базовом шаблоне: {% block content %}

Серия романов о Гарри Поттере

{% for book in books %}
{{book.number}}. "{{book.title}}" - {{book.date}}
{% endfor %}
{% endblock %} Тут же в цикле for (Twig for) мы проходимся по всем книгам, которые передали в данный шаблон с помощью записи $twig->render('books.html', array('books' => $books)); и для извлечения значений обращаемся к элементам массива по ключам: {{book.number}}, {{book.title}} и так далее. Таким образом, после срабатывания метода $twig->render('books.html', array('books' => $books)), Twig подгрузит шаблон books.html и сформирует html содержание. Далее он распознает, что books.html - это дочерний шаблон base.html, и поместит сформированное содержание в базовый шаблон. После всего этого Twig вернёт нам полноценную html страницу.

пятница, 10 января 2020 г.

MVC концепция. Во view делать проверку роли правильно?

#php #mvc


Интересует вопрос про концепцию MVC.

Есть пользователи и роли. Представьте себе, что во VIEW есть комментарии. 
Есть роли у пользователя user и admin.

Если роль user, тогда показывать просто комментарии, если роль пользователя admin
- тогда показывать иконку к каждому комментарию "edit".

Верно ли делать во VIEW проверку например, так:


Ответы

Ответ 1



Тут все немного более интересно. Этот код не должен быть целиком ни в представлении, ни в контроллере, ни в модели. Контроллер тем или иным способом должен получать объект пользователя - с помощью модели или просто из внешнего сервиса - и запихивать его в контекст представления. Сам контроллер в процессе создания и обработки пользователя не участвует никак, а просто передает его. В представлении же уже вызывается метод объекта пользователя - например, isAdmin(), который позволяет определить текущий статус пользователя, не прибегая к прямому сравнению, вынесет логику наружу, а для представления это будет сущствовать исключительно как флаг "истина/ложь". Конечно, это плохо масштабируется, поэтому с увеличением количества ролей можно либо создавать отдельные шаблоны (потому что все равно не получится хранить много ветвей в одном), либо создать некоторый AccessManager, у которого есть единственный метод hasAccessTo($user, $resourceKey) (или аналог), внутри которого спрятана вся логика по нахождению прав доступа. Обычно, впрочем, стараются все упростить до того, чтобы к моменту рендеринга все данные уже были известны, но если в коде представления запускается подобные функционал проверки - это не страшно.

MVC для игры морской бой

#cpp #mvc #проектирование


Разделил логику от интерфейса на составляющие MVC

Model:

Класс Game в котором реализованы игроки, у каждого игрока есть поле, корабли и так далее

View:

2 объекта класса TField (визуальный компонент)

Controller:

Класс GameController, который должен связывать логику игры и ходы с визуальным представлением
на форме.

Именно на контроллере стал задумываться, как связать их. Определить в классе GameController
объекты классов модели и визуального представления? Но как их связать? Обработку нажатия
на клетку в поле, отправку координат X и Y в класс Game и обратно получить ответ, обработав
попадание/не попадание?

Я частично понял, как реализовать все это. У нас есть цепочка:


  Представление -> Контроллер -> Модель


Представление вызывает клик и отправляет контроллеру событие о выстреле. Контроллер
передает информацию об это модели на обработку. Но как сделать обновление Представления
после изменений в Модели я так и не понял.

Я так понимаю, что нужно создать слушателя/-ей, которые будут вызываться из Модели
при обновлении данных. Но это значит, что Модель должна содержать ссылку на Представление,
что по сути перечит MVC, если Модель должна не знать о Представлении. Есть мысли?
    


Ответы

Ответ 1



Смотрите. Вам нужен по идее event или Listener, или как там этот паттерн называется. Суть такова. Модель выставляет метод Subscribe(), в который можно передать callback, который будет вызван при изменении свойства. Представление знает о модели, и подписывается на её изменения. Таким образом, модель ничего не знает о представлении, но может дёрнуть это самое представление, когда что-то поменялось. Пример на коленке: class Model { public: typedef int Token; Token subscribe(std::function callback) { max_token++; callbacks[max_token] = callback; return max_token; } void unsubscribe(Token token) { callbacks.erase(token); } private: std::map> callbacks; Token max_token = -1; // это дёрнет все callback'и void notifyall() { for (auto& kv : callbacks) kv.second(); } }; class View { Model* model; Model::Token token; //... View(Model* model) : model(model) { token = model->subscribe([this] { OnModelUpdate(); }); } ~View() { model->unsubscribe(token); } };

Один поток на action [закрыт]

#c_sharp #многопоточность #aspnet #mvc #async_await


        
             
                
                    
                        
                            Закрыт. На этот вопрос невозможно дать объективный ответ.
Ответы на него в данный момент не принимаются.
                            
                        
                    
                
                            
                                
                
                        
                            
                        
                    
                        
                            Хотите улучшить этот вопрос? Переформулируйте вопрос,
чтобы на него можно было дать ответ, основанный на фактах и цитатах, отредактировав его.
                        
                        Закрыт 3 года назад.
                                                                                
           
                
        
Читал на хабре статью про async/await и наткнулся на следующую строчку:


  Несмотря на то, что в ASP.NET нет выделенного UI потока, код в
  action-ах контроллеров не может выполняться более чем одним рабочим
  потоком одновременно.


Исходя из этой строчки у меня возникают вопросы:


Зачем так ограничивать action?
Как это реализовано внутрях? lock в ActionInvoker'е?

    


Ответы

Ответ 1



Вы просто не совсем правильно поняли мысль, котору пытался донести автор статьи. Он не пытался сказать, что один конкретный метод Action не может выполняться в нескольких потоках - ведь достаточно очевидно, что это не так. Если у вас пришел десяток одновременных HTTP-запросов на один и тот же Action - то это Action будет выполняться одновременно в 10 разных потоках. Никаких блокировок там нет. Автор статьи на хабре имел ввиду, что один конкретный запрос - один конкретный вызов Action для обработки конкретного запроса - будет выполняться одним конкретным рабочим потоком, к которому при этом будет привязан HttpContext этого самого запроса.

понедельник, 6 января 2020 г.

Вопрос про модель в MVC

#php #yii2 #mvc


Здравствуйте, я смотрел, как делают два разных человека сайт и так и не понял, откуда
брать данные из БД в модели или контроллере? ну, т.е. в модели мы пишем табл из который
будет выборка, это понятно.

Один человек делал так: в модели название табл и все. А выборку он делал уже в контроллере,
например: 

$feeds = Feedback::find()->orderBy('RAND()')->limit(4)->all();


А другой выборку делал в модели, а в контроллере уже обращался к методу того класса,
пример: 

$categories = Category::getCategoriesList();


Как правильно или как лучше и что лучше всего делать в модели?)))
    


Ответы

Ответ 1



Для примера возьмем ваш пример. Выводим $feeds = Feedback::find()->orderBy('RAND()')->limit(4)->all(); в контроллере и все работает. Завтра нужно тоже самое, но в другом контроллере (или методе)? Что тогда? Вот если мы создадим метод в модели, то сможем использовать все это и в других контроллерах. public function getFeeds() { return self::find()->orderBy('RAND()')->limit(4)->all(); } Тут даже дело уже не в самом MVC, а в подходе к гибкости системы. Старайтесь всегда думать о том, что вдруг данный код понадобиться где-то ещё. Я использую помимо моделей (Models) ещё и модели представления (ViewModels). Это очень удобно. Например есть модель Users: class Users extends ActiveRecord { public static function tableName() { return 'users'; } //Behaviors... //Roles... //Relations } В данной модели я храню все методы, касаемо самого Yii (правила,связи, поведения и т.д.). Не засоряю данный класс. Для остальных же методов использую UsersViewModel: class UsersViewModel extends Users { public static function getAllUsers() { return Users::find()->all(); } } Я привел для примера примитивный пример, но важна сама суть. Старайтесь всегда думать на шаг вперед, чтобы потом не возвращаться на 2 шага назад. Лучшие практики MVC. На примере Yii

Ответ 2



Все очень просто. Согласно правилам MVC - контроллер является посредником между view и моделью и по сему модель вызывает контроллер и уже из подгруженной модели передает данные. Сие есть правильно. А в модели нужно описывать связи с другими моделями или поведение этой модели.

Несколько моделей для 1 контроллера и представления

#c_sharp #aspnet_mvc #mvc


Пишу на asp.net mvc. 

В одном view должна быть целая куча записываемых и показываемых данных, по-этому
мне было бы очень удобно разделить модель на много маленьких моделей по категориям,
что бы было легче ориентироваться их полях. 

Однако так как это надо сделать все в одном view, которое может иметь только одну
модель, такой способ не прокатит. 

Как можно это реализовать иначе?
    


Ответы

Ответ 1



В таких случаях (сложное представление состоит из множества блоков) обычно во вьюхе делают partial view с отдельными маленькими модельками.

Ответ 2



Как было сказано выше, разбейте view на несколько partial views. Что касается передачи данных с сервера в эти частичные представления (partial views), то можно создать несколько классов (по одному для каждого частичного представления, ну или в зависимости от необходимости/целесообразности/предпочтений и т.д.). Создайте модель для главного представления (большой view), которая будет содержать типы созданных вами ранее моделей для частичных представлений. И на вьюхе передавайте эти модели (свойства основной большой view model) в соотвествующие частичные представления.

воскресенье, 5 января 2020 г.

Помогите понять разницу между моделью и контроллером в MVC

#mvc


Очень нубский попрос. Почитал вики, различные разжевывания концепции, часто видел
реальные примеры, но кое-что все-таки не дает покоя. Хочется раз и навсегда прояснить
тонкости. По какому принципу отделяются функции в контроллере от функций в модели?
Правильно ли я понимаю, что в контроллере должны быть методы, которые инициируются
каким-либо событием, а в модели - все остальные (т.е., грубо говоря, если нам не нужно
больше одного метода на какое-то событие, напр. открытие новой страницы, можно написать
этот метод в контроллере и это будет правильно)? Если же логика сложна и одним небольшим
методом не обойтись, то можно:
 - использовать метод в контроллере как обертку для вызова метода модели
 - вызвать вспомогательные методы в модели, работающие с данными
?
P.S. Методы для работы с СУБД - тут я бы выносил их в отдельную библиотечку. Просто
потому, что хранить их в модели неправильно. И получается, что в моем представлении
модель в любом случае по объему получается меньше контроллера, хотя теоретически должно
быть наоборот.    


Ответы

Ответ 1



Правильно ли я понимаю, что в контроллере должны быть методы, которые инициируются каким-либо событием В общем - да а в модели - все остальные (методы) ... Методы для работы с СУБД - тут я бы выносил их в отдельную библиотечку. Не все. У контроллера, модели и представления есть свои разграниченные области - связка запросов, модели и представления; работа с данными; вывод. Все остальное лежит на внешних библиотеках, и MVC слабо волнует, что в этих библиотеках происходит, пока они выполняют свои функции. Модель не включает в себя БД, БД - это провайдер данных, модель могла бы брать эти данные и из другого сервиса, и из json-файлов, в этом случае провайдерами были бы сетевая передача и десериализация данных или функции файловой системы и json-парсер. В большинстве случаев этот провайдер тесно интегрирован с моделью (потому что предполагается, что работа всегда будет с БД, и сложно сильно абстрагироваться от SQL-запросов так, чтобы запрос к тому же json-файлу и БД был одинаковым), но в теории можно создать интерфейс этого провайдера, и вынести БД из модели полностью. т.е., грубо говоря, если нам не нужно больше одного метода на какое-то событие, напр. открытие новой страницы, можно написать этот метод в контроллере и это будет правильно Вообще - да. Иногда получается так, что контроллер приходится делить для повышения читаемости (например, страница должна отдаваться в произвольном формате, и ajax-запросы отдаются на один контроллер, а обычные - на другой), но обычно подобное - это красный флаг с надписью "что-то явно делается не так". Но, конечно, в контроллер действия попадают не просто потому что там нужно "не больше одного метода", а потому что это событие - это запрос, и его надо обработать. Если же логика сложна и одним небольшим методом не обойтись, то можно: - использовать метод в контроллере как обертку для вызова метода модели - вызвать вспомогательные методы в модели, работающие с данными ? В целом все верно, просто, опять же, деление должно происходить не по количеству вызовов, а по логике приложения. Какие-то вещи, например, проверку прав доступа, надо производить в контроллере, просто это стоит вынести в базовый класс. А вообще - да, чем тоньше контроллер, тем легче работается и больше когда повторно используется. И часто бывают случаи, когда контроллер состоит из пары строчек и действительно является не более, чем оберткой. Очень нубский попрос. Почитал вики, различные разжевывания концепции, часто видел реальные примеры, но кое-что все-таки не дает покоя. Хочется раз и навсегда прояснить тонкости. Это нормально, у меня тоже понимание довольно долго приходило, а "Где же должна лежать такая-то функция?" - стандартная тема для дев-срача. Тут нет однозначного твердого стандарта, и критерии оценки верности решений могут быть косвенными - если все легко и удобно расширяется, встраивается, рефакторится и очевидно отсутствие костылей, то все в порядке. Но если в контроллере почему-то форматируются свойства модели, то тут вопросов по поводу корректности быть не должно.