• Правильно ли реализован класc?

    Fesor
    @Fesor
    Full-stack developer (Symfony, Angular)
    Пишу свою модель MVC


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

    и мне кажется что я делаю что-то не так и хочется его добить


    Давайте сначала по мелочам:

    if ( !defined( 'FILE_COMPILE' ) )

    убрать. Если вы собираетесь "конкатенировать PHP" - не делайте этого. Есть opcache.

    if ( !class_exists ( 'Controller' ) ) {

    composer и PSR-4 совместимая автозагрузка классов.

    class Controller extends UDAPI {

    Наследование классов (extends) - плохо (ну опять же в подавляющем большинстве случаев). Наследование типов (implements) - хорошо. Приучайте себя использовать наследование классов как крайнюю меру.

    Ну и опять же, что это за UDAPI от которого вы наследуете контроллер? Не выгоднее ли передать его в конструктор контроллера как зависимость?

    protected $uri;
        protected $params = array();
        protected $request = array();


    сделайте отдельный класс Request и инкапсулируйте работу с ним там.

    $this->uri = filter_input ( INPUT_SERVER, 'REQUEST_URI', FILTER_SANITIZE_URL );
        $this->uri = trim ( $this->uri, '/\\' );
        $this->uri = urldecode ( $this->uri );
        $this->uri = parse_url ( $this->uri, PHP_URL_PATH );


    Опять же, это не задача контроллера. Контроллер пусть принимает уже готовый объект запроса.

    if ( $this->uri == '' )
            $this->redirect ( $this->config->root_uri . $this->default[ 'controller' ] . '/' . $this->default[ 'action' ], true );


    Почитайте про мидлвэры, про фронт-контроллеры, про Model-View-Adapter. Последняя схема куда лучше вписывается в модель HTTP сервера.

    public function ready ( ) {

    сделайте отдельный компонент - роутер. Кто-то (например фронт контроллер) должен просить роутер узнать какой контроллер дергать. И потом уже дергать этот контроллер. Не надо пихать все в одну хрень, тем самым вы нарушаете саму идею "разделения ответственности" пытаясь реализовать конкретную реализацию этого принципа.

    $this->setController ( array_shift ( $this->pattern ) );
    $this->setAction ( array_shift ( $this->pattern ) );


    Пара слов о состояние. Состояние это сложность. То есть посмотрев на переменную `$this->pattern` мы понятия не имеем что там хранится поскольку с течением времени его значение меняют. Причем зачем меняют - непонятно.

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

    call_user_func_array ( array ( $controller, $this->action ), $this->request );


    На дворе PHP7 между прочим.

    } else {
                echo '404 error';
              }


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

    public function isController ( $controller ) {
        if ( is_dir ( SOURCE_DIR . '/controllers/' . $controller . '/' ) ) {


    ... PSR-4, классы... автозагрузка...

    public function getModel ( $controller ) {

    Для 2006-ого года в целом нормально, но это ж 10 лет назад.
    Ответ написан
    2 комментария
  • Объясните как правильно применять паттерн Repository с Entity Framework?

    Fesor
    @Fesor
    Full-stack developer (Symfony, Angular)
    зачем нужно делать свой repository на каждую сущность


    Не на каждую сущность а только для сущностей, которые выступают корнями агрегатов сущностей. Ну то есть если у вас есть сущность Product и ProductImage к примеру, то репозиторий вы делаете только для продуктов.

    Почему нельзя использовать шаблон Repository для работы с несколькими сущностями сразу


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

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

    И для каждой сущности будут свои правила как и кто может их где хранить. Банальное соблюдение принципа единой ответственности и разделения обязанностей.
    Ответ написан
    Комментировать
  • Откуда информация о быстрой порче SSD?

    Fesor
    @Fesor
    Full-stack developer (Symfony, Angular)
    Порча от swap - это миф?


    Давайте так. Порча от swap - это миф. Порча от частых перезаписей - не миф. Ячейки деградируют, SSD портится... со временем. Для домашнего ноутбука это время вполне может быть больше средней жизни ноутбука у человека.

    Если у вас мало оперативки - swap на ssd вполне себе нормальное решение. Но только это будет означать что использоваться он будет намного более интенсивно нежели в системах с большим объемом памяти.

    Словом как бы вы не изощрялись, а бэкапы важных данных вам стоит делать в любом случае и тогда в целом пофигу.
    Ответ написан
    4 комментария
  • Сколько занимает переменная, если она равна undefined?

    Fesor
    @Fesor
    Full-stack developer (Symfony, Angular)
    Занимает ли эта переменная какое-то место в памяти


    Да. undefined это всего-лишь значение специального типа. Переменная же будет выступать в роли контейнера для этого значения (и любого другого). И контейнер сам по себе занимает какую-то память. Как много - зависит от конкретной реализации и ситуации.

    Другое дело что оптимизирующий компилятор может тупо вырезать код с переменной, которая не используется.
    Ответ написан
    4 комментария
  • Есть ли у кого примеры использования Beanstalkd в Symfony через bundle Pheanstalk?

    Fesor
    @Fesor
    Full-stack developer (Symfony, Angular)
    Используйте https://github.com/bernardphp/BernardBundle

    Хотелось бы в идеале, чтобы можно было в очередь отправить job-у, в которой будет указано - название сервиса Symfony,


    Лучше какой-то идентификатор джобы, ибо как-то не логично что задача знает кто ей будет заниматься. Ну то есть вам приходит какая-то задача с каким-то типом, и какой-то роутер разрулит какой сервис будет ею заниматься.
    Ответ написан
    Комментировать
  • Как реализовать объект с методами, которые можно было бы вызывать последовательно?

    Fesor
    @Fesor
    Full-stack developer (Symfony, Angular)
    Возможно вам стоит конкретизировать пример, поскольку то что вы хотите проще делать так:

    var el = document.querySelector('#id .selector span:first-of-type')
    Ответ написан
    3 комментария
  • Как реализуется принцип открытости/закрытости в случае "ветвления" расширений в Java?

    Fesor
    @Fesor
    Full-stack developer (Symfony, Angular)
    основной — наследование.


    Наследование типов а не классов. То есть через интерфейсы.

    В Java нет множественного наследования.


    В Java есть возможность делать композицию типов путем имплементации множества интерфейсов. А с учетом того что в Java8 у вас теперь есть возможность делать "дефолтные" имплементации методов в интерфейсах - у вас есть "правильное" наследование.

    Через некоторое время, этот класс захотят расширить по OCP — унаследуются, и сделают класс Бармен.


    А как потом быть если мы захотим сделать робота бармена? Я это к тому что "человек" не всегда будет являться базовым типом "бармена".

    В целом Dmitry Roo вам верно сказал. "Бармен" это профессия. Свойство человека. У человека может быть много профессий:

    class Human
    {
        Profession[] professions;
    }


    Таким образом мы можем крутить и вертеть как хотим.
    Ответ написан
    Комментировать
  • PHP функциональный язык или объектно-ориентированный?

    Fesor
    @Fesor
    Full-stack developer (Symfony, Angular)
    Я могу дать вам лишь мой вариант ответа собеседующему:

    Никаким. Отличительная черта PHP в том, что он не задумывался как язык программирования. Это даже в названии отражено - PHP (recursive acronym for PHP: Hypertext Preprocessor).

    На этапе PHP3 это был уже полноценный процедурный язык программирования, где писать логику можно было уже не на Си.

    В PHP4 в язык были введены "классы" чтобы дать механизм изоляции состояния. Это еще нельзя было называть ООП просто потому, что... это не объекты а классы. Нет ни инкапсуляции, есть только ad-hoc полиморфизм (который есть у всех языков с динамической системой типов) и ограниченный полиморфизм подтипов. Ну а наследование классов и так признано ненужной штукой в контексте ООП.

    В PHP5 наконец-то были введены интерфейсы, и теперь можно было делать нормальный полиморфизм. Были введены модификаторы доступа и т.д. но язык все еще остается процедурным по большому счету (и это нормально, поскольку все существующие ОО языки являются процедурными).

    В PHP5.3 были введены анонимные функции. но без лексический скоупов, без функций высшего порядка делать "чистую функциональщину" просто не выйдет. Во всяком случае это будет неудобно.

    Отсюда сделаем вывод - PHP на сегодняшний день, процедурный язык программирования, имеющий достаточно возможностей чтобы практиковать все основные парадигмы программирования просто с разной степенью удобства.
    Ответ написан
    Комментировать
  • Где осуществлять валидацию пользовательского ввода в архитектуре MVC?

    Fesor
    @Fesor
    Full-stack developer (Symfony, Angular)
    Давайте размышлять что такое валидация и зачем она нам нужна:

    Нам нужно проверять, не нарушаются ли пред-условия для действий или инварианты состояний. Например - пользователь всегда должен иметь email - такие правила можно запихивать на уровне конструктора класса пользователя. Тогда у нас не будет физически возможности "создать" пользователя не указав email. Что бы убедиться что переданная строка email - мы можем опять же завернуть "примитив" в свой тип Email, таким образов сделав подтип строк, который гарантирует нам, что любая штука относящаяся к этому типу будет являться email-ом.

    Такие правила как "у пользователя должен быть уникальный email" могут быть проверены только там, где достаточно информации. Например - некий репозиторий пользователей, или DAO. При попытке "сохранить" мы уже делаем проверку. Или мы можем делать это просто повесив ограничение на уникальность на уровне базы данных. Это уже не столь важно.

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

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

    В простых случаях, когда данные из запроса втупую мэпятся на "модель данных", мы можем проверять уже результат. Но в случае с логикой сложнее CRUD это уже не выйдет. Точнее это уже чуть сложнее. К примеру мы передали несуществующий айдишник связанной сущности. Мы запросим данные, получим нул, и валидатор выдаст нам что-то вроде "Извините, но вот эта штука обязательна к заполнению". А пользователь такой "чтааа? Я ж заполнил!" Вот если бы ему приходило сообщение мол "Выбранная вами штука не существует" - тогда ладно, но подавляющее большинство так не запаривается.

    Словом... тут нужно исходить не из "где это делается в MVC" а из "а кому это нужно и какие цели вы приследуете".

    Если что, MVC это не все приложение, это лишь способ разделить ответственность. Приложение ничего не должно знать о UI и все. То есть валидация входящих данных вполне может лежать на уровне контроллера поскольку это ему нужно сформировать список ошибок и запихнуть их к полям формы. С другой стороны, часть валидации может происходить вообще вне "MVC", где-то внутри, на уровне модели предметной области.

    Нельзя из букв "M", "V" и "C" составить слово вечность. Именно по этой причине MVC как подход для организации GUI уже лет 20 как не используется в чистом виде.
    Ответ написан
    Комментировать
  • Как выбирать направление архитектуры ООП приложения?

    Fesor
    @Fesor
    Full-stack developer (Symfony, Angular)
    и как отдельный класс-синглтон


    Зачем? Зачем сингелтон? Ответте на вопрос когда это нужно?

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


    - Разделение ответственности - важный принцип инженерного дела в принципе.
    - Принципы SOLID - хорошо дают понять как работать с зависимостями и делать декомпозицию системы. Сильно пересекается с инкапсуляцией, полиморфизмом и разделением ответственности.
    - Паттерны GRASP - эдакая смесь принципов и паттернов, описывают нюансы цикла жизни объектов и их взаимодействия друг с другом.
    - Закон Деметры - про инкапсуляцию.
    - CQRS - подход по разделению операций записи и операций чтения. Естественно подход такой не работает если вам надо реализовать атомарную запись и чтение, но это минимальный набор задач.
    - Рефакторинг. Он нужен всегда. Его нужно делать по чуть-чуть когда видно что "уже мешает" или "можно было сделать лучше". Ну то есть это не переписывание всего и вся большими кусками, а маленькие изменения которые с течением времени эволюционно меняют архитектуру проекта. Возможно только если код покрыт тестами, это отдельная жирная тема.

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

    https://en.wikipedia.org/wiki/Category:Programming...
    Ответ написан
    2 комментария
  • CommonJS / RequireJS - зачем?

    Fesor
    @Fesor
    Full-stack developer (Symfony, Angular)
    Плюс в каких ситуациях такие инструменты должны быть нужны и вообще зачем нужны все эти dependency injection?


    Инверсия управления. Управление зависимостями, снижение связанности между компонентами системы. Что бы то что должно зависить зависило от чего-то и наоборот.

    Не нужно думать что есть универсальные подходы. Есть разные подходы, каждый из которых имеет свои плюсы и минусы.
    Ответ написан
    Комментировать
  • Как работать с данными?

    Fesor
    @Fesor
    Full-stack developer (Symfony, Angular)
    встал вопрос как в нем работать с данными


    Любым удобным для вас способом. SIlex это тупо http фреймворк, он не предоставляет ничего из коробки для работы с базой данных. Юзайте хоть PDO хоть ORM любую.

    слышал что есть какие-то провайдеры


    Сервис провайдеры, они используются для регистрации зависимостей. Читайте документацию.

    Вообщем мне нужен некий класс который инкапсулирует работу с данными


    Это не один класс как правило, далеко не один. Либо читайте про DAO/TableGateway.

    и чтобы в дальнейшем использовать его методы в контроллерах


    Контроллеры служат одной цели. Сконвертить результат работы приложения в HTTP ответ или из HTTP ответа сформировать обращение к приложению. Ну то есть "приложение" - это просто какой-то php код. При помощи сервис провайдеров вы можете регистрировать код в контейнере зависимостей и брать нужный в контроллерах.

    Попробуйте разобраться сначала с тем, что такое сервис локатор, инъекция зависимостей, инверсия управления... И не думайте что есть "правильный" способ работы с базой данных в silex. Там просто нет работы с базой данных из коробки.
    Ответ написан
    Комментировать
  • По какой причине при сохранении сущности с отношением one to many, не записывается id на связь?

    Fesor
    @Fesor
    Full-stack developer (Symfony, Angular)
    Картинкам не надо знать о продуктах. Минимизируйте количество двусторонних ассоциаций.

    Так же почитайте про каскадные персисты.

    p.s. Подобные вопросы следует удалять так как "легко гуглится" или просто достаточно прочитать документацию. Не ленитесь иначе все будет и дальше плохо.
    Ответ написан
  • Правильный ли, подход к проектированию приложения в symfony 3?

    Fesor
    @Fesor
    Full-stack developer (Symfony, Angular)
    Не правильный. Читайте Эрика Эванса. Читайте про unit of work. Читайте про "save your repositories from save".
    Ответ написан
    Комментировать
  • Как организовать структуру модульных проектов?

    Fesor
    @Fesor
    Full-stack developer (Symfony, Angular)
    Найдите баланс между Coupling и Coheasion.

    Забудьте о классах и будет проще. Тогда все - модули. Приложение - модуль. Оно состоит из других модулей. Те используют другие модули и так далее организуем иерархию модулей. Классы это просто способ создания новых типов данных, для организации кода оно используется только в языках, где нет модулей (не ООП, а просто структурная единица кода, как в C++ например).

    Они конечно позволяют организовать пространство имён


    Пространства имен нужны тогда, когда все лежит в глобальной области видимости. Когда все существует в контексте модулей оно не нужно. У вас и так есть изоляция необходимая.

    Вся задача сводится к тому, чтобы максимально порезать систему таким образом, чтобы полностью контролировать кому что доступно и кто чем пользуется. Декомпозиция в чистом виде, ну и инкапсуляция.
    Ответ написан
  • Как правильно работать с объектами выборки doctrine в Symfony?

    Fesor
    @Fesor
    Full-stack developer (Symfony, Angular)
    дополню ответ Юрий

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


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

    По поводу коллекций, в Doctrine есть такая штука как Collection. Вы должны понимать что в доктрине вы оперируете не табличками в базе, а объектами. Строите именно объектную модель вашей системы. В этом ключе можете почитать что такое "агрегат сущностей". В вашем случае у вас агрегат будет состоять из двух сущностей. Product и его Image. Например если вы захотите сделать добавление картинок, вы можете сделать так:

    /**
     * usage: $product->addImage($image);
     */
    public function addImage(Image $image)
    {
        $this->images->add($image);
    }


    А коллекция сама выполнит persist новой сущности. Таким образом количество репозиториев уменьшается до количества корней агрегатов сущностей. В вашем примере "корнем", то есть вершиной графа взаимоотношений объектов в контексте продуктов, является сам продукт. А потому репозиторий мы будем делать только для продуктов. Все остальное внутри оного разруливается либо при помощи коллекций.

    При работе с доктриной вообще полезно представлять себе, что никакой базы данных у вас нет. Что данные просто живут между запросами где-то там, в памяти. Это должно помочь вам "абстрагироваться" и перестать смешивать "сущности" и "таблицы".

    К примеру "новички" в доктрине любят персисть сущность даже для обновления. Они путают `persist` и `save`. Так вот, если вы загрузили сущность из базы через доктрину, то сущность уже попадает в unit of work. И делать persist уже не нужно, этот метод только для того чтобы доктрина узнала о чем-то новом. А так она и так знает про эту сущность. В итоге вы можете просто что-то поменять и вызвать flush. То есть репозиторий - это тупо хранилище. Хранилище умеет хранить. Изменять то, что оно хранит оно не может.

    Так же рекомендую на тему репозиториев почитать это:

    www.whitewashing.de/2013/03/04/doctrine_repositori...

    Ну и в целом.

    https://www.youtube.com/watch?v=rzGeNYC3oz0 - доклад о том как готовить доктрину от авторов оной.

    От себя лишь добавлю простые правила:

    - Не используйте напрямую доктриновские репозитории. Пишите свои, а в них уже юзайте доктриновские. Не стоит размазывать доктрину по всему проекту, потом это будет нереально поддерживать.
    - Не наследуйтесь от EntityRepository. Это внутренний механизм доктрины общего назначения. Используйте их в своих репозиториях со своим интерфейсом, повышая специфичность и ужесточая контроль за тем кто что юзает.
    - Старайтесь использовать entity manager только в своих репозиториях и каких то небольших сервисах. Не размазывайте все по всюду.

    что очень сильно срет память.


    Доктрина гарантирует вам что в памяти будет всегда только один инстанс сущности. То есть если у вас есть 10 объектов одного типа и имеющих один объект, это все будут ссылки на одну сущность. В вашем случае у вас просто циклическая ссылка между продуктами и изображениями. dump циклические ссылки не особо умеет.

    Это логичное ограничение, дабы не возникало ситуаций что вы обновили что-то в одном экземпляре сущности и что-то в другом, и в базу попадут только часть изменений. За подробностями - читайте документацию к доктрине в отношении UnitOrWork и Identity Map.
    Ответ написан
  • Как правильно разделять бэкенд и фронтэнд в сложных веб-приложениях?

    Fesor
    @Fesor
    Full-stack developer (Symfony, Angular)
    SPA - полноценное самодостаточное приложение, а потому вынести это добро в отдельный репозиторий - вполне себе нормальное решение. Аналогия - разработка мобильных приложений и бэкэнда к оному. Вести такую разработку в одном репозитории как минимум будет неудобно.

    И если с мобильными приложениями все понятно, то с фронтэндом могут быть замуты. Например, вы хотите сделать страничку логина просто на Symfony/Django, и потом редиректить уже на SPA после того, как будет получен аутентификационный токен.

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

    или еще интереснее. Какой-то прелоад данных. Например мы можем захотеть заинлайнить в html какие-то данные, которые генерит бэкэнд. Чтобы эти данные были доступны клиенту еще до того, как загрузится ангуляр. В этом случае опять же мы можем генерить точку входа при помощи готового html шаблона, поставляемому нам со стороны фронтэнда и силами какого-нибудь twig/jninja инлайнить json в тело страницы:

    function data() {
        return {{data | json}};
    }


    Но это оооочень редкие кейсы.
    Ответ написан
    3 комментария
  • Отличия абстрактного класса от интерфейса?

    Fesor
    @Fesor
    Full-stack developer (Symfony, Angular)
    В чем отличие абстрактного класса от интерфейса в Java?


    Все упирается в понятие "тип". В былые времена, то есть во времена языка Simula, из которого черпали вдохновение создатели C++, были только классы. И на классах базировалась система типов. Причем механизм наследования был реализован так, как реализован, исключительно для экономии памяти, которая в те времена была очень дорогой.

    Для того чтобы достичь полиморфизма, мы должны иметь возможность объявлять абстрактные типы. Мол "любая хрень которая имеет такой тип будет работать как надо". Потому в языках типа C++ появились абстрактные классы. Поскольку иногда нам хочется делать композицию абстрактных типов, в C++ реализовали множественное наследование.

    В Java, которая во многом черпала вдохновения из C++ и smalltalk, решили ввести еще одну сущность - интерфейсы. Это был своего рода упрощенный способ задать абстрактный базовый тип. По итогу чтобы не решать проблему бриллианта (или ромба) от множественного наследования было решено отказаться и дать возможность классам имплементить несколько интерфейсов.

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

    В целом абстрактные классы нужны тогда, когда вам нужно наследование. Обычно это в ситуациях, когда у вас есть несколько классов, которые должны иметь общий абстрактный тип (то есть нельзя выделить наиболее слабого по ограничениям предка). Например если мы делаем цепочку классов String <- Email, то тут нет смысла в абстрактных классах так как тип String уже включает в себе подмножество типов Email.

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

    Так же рекомендую к прочтению: www.javaworld.com/article/2073649/core-java/why-ex...
    Ответ написан
    9 комментариев
  • Как реализовать систему плагинов на TypeScript?

    Fesor
    @Fesor
    Full-stack developer (Symfony, Angular)
    пусть тот кто добавляет плагин явно прописывает его в зависимостях какого-то модуля. Явное всегда лучше чем неявное.
    Ответ написан
    1 комментарий
  • Как работает Docker с точки зрения сети?

    Fesor
    @Fesor
    Full-stack developer (Symfony, Angular)
    ведь все запросы будут падать на выделенный ip, которые должен проксировать получается на docker контейнер?


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

    https://fralef.me/docker-and-iptables.html - вот тут можете по подробнее почитать как это работает.
    Ответ написан
    Комментировать