• Почему continue_if_empty не работает для FileInput?

    @novrm
    /**
     * Configuration of the input filter for element based on the provided specification.
     * Specification can contain any of the following:
     *
     * .-------------------.----------------.-----------------.-----------------.--------------------.
     * | continue_if_empty | required       | allow_empty     | Is empty valid? | Apply other filter |
     * |-------------------+----------------+-----------------+-----------------+--------------------|
     * | false (default)   | true (default) | false (default) | false           | Not                |
     * | false (default)   | true (default) | true            | true            | Not                |
     * | false (default)   | false          | false (default) | true            | Not                |
     * | true              | true (default) | false (default) | true            | Yes                |
     * |-------------------+----------------+-----------------+-----------------+--------------------|
     * | false (default)   | false          | true            | true            | Not                |
     * | true              | true (default) | true            | true            | Yes                |
     * | true              | false          | false (default) | true            | Yes                |
     * | true              | false          | true            | true            | Yes                |
     * '-------------------'----------------'-----------------'-----------------'--------------------'
     */
    Ответ написан
    Комментировать
  • Как реализовать роутинг PHP MVC?

    @novrm
    В любом большом веб-приложении есть потребность в иерархии...
    Пример - интернет магазин - две основные МОДЕЛИ (Model) - Category и Product:

    Бытовая техника (Category)
    |---------- Холодильники (Category)
    __________|__________ Samsung2019 (Product)
    |__________ Телевизоры (Category)
    ____________|__________ Sony2019 (Product)

    Как вывести в броузер (придумать единственный URL) переменные ВИДА (View) о Sony2019.
    ... существует миллион и один способ это сделать - все зависит от фантазии веб-программиста и желания заказчика.

    Например так:
    market.com/sony2019
    market.com/sony2019/
    market.com/sony2019.html
    market.com/p201569-sony2019.html

    Эти варианты - попроще, легко реализуются и веб-программист будет настаивать на таком положении вещей...
    Однако заказчик желает иметь УРЛы SEO-правильные, как ему нашептал Лебедев...
    ... и веб-программист получает головняк:
    market.com/Бытовая техника/Телевизоры/sony2019
    market.com/Бытовая техника/Телевизоры/sony2019.html

    Как это работает...
    Все УРЛы съедаются КОНТРОЛЛЕРОМ (Controller) в простейшем случае...
    Однако в фреймворках перед КОНТРОЛЛЕРОМ может быть РОУТЕР - куда УРЛы попадают еще раньше...
    URL -> ROUTER -> CONTROLLER -> MODEL -> VIEW

    Вот в этой цепочке "перетравливается" УРЛ... Как из SEO-URL иерархической цепочки получить искомые ВИДИ - существует миллион и один способ...

    Например так...
    Задаете для ROUTER
    - если URL заканчивается на слеш "/" - то перенаправляй на контроллер CategoryController - ибо получили КАТЕГОРИЮ... Например "market.com/Бытовая техника/Телевизоры/"
    - если URL НЕ заканчивается на слеш "/" - то перенаправляй на контроллер ProductController - ибо получили ПРОДУКТ... Например "market.com/Бытовая техника/Телевизоры/sony2019"

    Дальше в CategoryController берем часть URL, например "Бытовая техника/Телевизоры" и придумываем алгоритм - извлечь МОДЕЛЬ "Телевизоры", которая является ребенком для МОДЕЛИ "Бытовая техника"... Извлекаем МОДЕЛЬ из БД - передаем ее переменные в ВИД или помощники вида...

    Аналогично для МОДЕЛИ "sony2019" Берем часть URL, например "Бытовая техника/Телевизоры/sony2019" и придумываем алгоритм - извлечь МОДЕЛЬ "sony2019", которая является ребенком МОДЕЛИ "Телевизоры", которая является ребенком для МОДЕЛИ "Бытовая техника"... Извлекаем МОДЕЛЬ из БД - передаем ее переменные в ВИД или помощники вида...
    Ответ написан
    Комментировать
  • Как запустить ZendFramework?

    @novrm
    Регистрация и автозагрузка классов для ZF3 теперь осуществляется через composer.

    Было для ZF2 index.php:
    <?php
    /**
     * This makes our life easier when dealing with paths. Everything is relative
     * to the application root now.
     */
    chdir(dirname(__DIR__));
    // Decline static file requests back to the PHP built-in webserver
    if (php_sapi_name() === 'cli-server' && is_file(__DIR__ . parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH))) {
        return false;
    }
    // Setup autoloading
    require 'init_autoloader.php';
    // Run the application!
    Zend\Mvc\Application::init(require 'config/application.config.php')->run();


    Стало для ZF3 index.php:
    <?php
    use Zend\Mvc\Application;
    use Zend\Stdlib\ArrayUtils;
    /**
     * This makes our life easier when dealing with paths. Everything is relative
     * to the application root now.
     */
    chdir(dirname(__DIR__));
    // Decline static file requests back to the PHP built-in webserver
    if (php_sapi_name() === 'cli-server') {
        $path = realpath(__DIR__ . parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH));
        if (__FILE__ !== $path && is_file($path)) {
            return false;
        }
        unset($path);
    }
    // Composer autoloading
    include __DIR__ . '/../vendor/autoload.php';
    if (! class_exists(Application::class)) {
        throw new RuntimeException(
            "Unable to load application.\n"
            . "- Type `composer install` if you are developing locally.\n"
            . "- Type `vagrant ssh -c 'composer install'` if you are using Vagrant.\n"
            . "- Type `docker-compose run zf composer install` if you are using Docker.\n"
        );
    }
    // Retrieve configuration
    $appConfig = require __DIR__ . '/../config/application.config.php';
    if (file_exists(__DIR__ . '/../config/development.config.php')) {
        $appConfig = ArrayUtils::merge($appConfig, require __DIR__ . '/../config/development.config.php');
    }
    // Run the application!
    Application::init($appConfig)->run();
    Ответ написан
  • Как подключить doctrine к zend expressive?

    @novrm
    Как-то так: https://github.com/doctrine/DoctrineORMModule#conn...
    <?php
    return [
        'doctrine' => [
            'connection' => [
                'orm_default' => [
                    'driverClass' => \Doctrine\DBAL\Driver\PDOMySql\Driver::class,
                    'params' => [
                        'host'     => 'localhost',
                        'port'     => '3306',
                        'user'     => 'username',
                        'password' => 'password',
                        'dbname'   => 'database',
                        'driverOptions' => [
                            \PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES \'UTF8\'',
                        ],
                    ],
                ],
            ],
        ],
    ];
    Ответ написан
    Комментировать
  • Как в Doctrine засетить переменную при подключение?

    @novrm
    Нечто похожее реализовано в модуле запоминания регистрации пользователя.
    Процедура происходит одновременно как через сессии так и через Doctrine.
    goalio/GoalioRememberMe
    goalio/GoalioRememberMeDoctrineORM
    Ответ написан
    Комментировать
  • Чем различаются ServiceManager и ModuleManager?

    @novrm
    Если рассматривать проект в виде "пирамиды", то...

    На вершине - веб-приложение - отображение которого есть сайт.

    Модуль - самодостаточный единичный "блок" веб-приложения; функционально завершенный php-код которого может состоять из моделей, видов, контроллеров, сервисов и прочее... Модуль расширяет функциональные возможности веб-приложения и может функционировать лишь "внутри" веб-приложения.
    ModuleManager - контейнер для манипуляций модулями.

    Сервис - "механизм" в модуле, для манипуляций между моделями, контроллерами, видами, прочее...
    ServiceManager - контейнер для манипуляций сервисами.
    Ответ написан
  • Где может понадобиться трейт в PHP?

    @novrm
    Пример номер один - трейт для внедрение через сеттер и геттер сервис менеджера.
    ... или других сервисов в другие сервисы.

    use Zend\ServiceManager\ServiceLocatorInterface;
    
    /**
     * ServiceManagerAwareTrait trait.
     */
    trait ServiceManagerAwareTrait
    {
        /**
         * $serviceManager instance.
         * @var ServiceLocatorInterface
         */
        protected $serviceManager = null;
    
        /**
         * Set $serviceManager.
         *
         * @param  ServiceLocatorInterface $serviceManager
         * @return self
         */
        public function setServiceManager(ServiceLocatorInterface $serviceManager)
        {
            $this->serviceManager = $serviceManager;
    
            return $this;
        }
    
        /**
         * Retrieve $serviceManager.
         *
         * @return ServiceLocatorInterface $serviceManager
         */
        public function getServiceManager()
        {
            return $this->serviceManager;
        }
    
    }


    Номер два - наследовать вы можете только ОДИН класс, а трейтов - МИЛЛИОН и тележку...
    Вот у вас есть сервис, который вы обязаны унаследовать от некого стандартного класса...
    ... но желаете добавить еще несколько методов...
    Что тогда?
    Стандартный класс - кем то написан и является неизменяемой частью некого модуля - править нельзя.
    Нужно - унаследовать ДВА раза - один раз наследовать расширенный класс, другой раз - непосредственно от расширенного - наследовать рабочий класс...
    ... или использовать трейты - элегантное решение.

    Правда - есть несколько но - говорят, что при внедрении сложного трейта - тяжело писать тесты, ну и старые версии php их не поддерживают...
    А так - очень даже упрощает жизнь.
    Ответ написан
    1 комментарий
  • Как сделать кнопку на закрытие активного tab bootstrap?

    @novrm
    Попробуйте юзать стандартную кнопку "close".
    <ul class="nav nav-pills">
      <li role="presentation" class="active"><a href="#">Home</a></li>
      <li role="presentation"><a href="#">Profile</a></li>
      <li class="alert" role="presentation">
        <a href="#">
          <button type="button" class="close pull-right" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">&times;</span></button>
          Messages
        </a>
      </li>
    </ul>
    Ответ написан
  • Doctrine2. Как выбрать и гидрировать связанные коллекции?

    @novrm
    В репозитории сущности Category создаете метод типа getCategory, где создаете подобный запрос.
    Вот только сортировка и количество разных под-коллекций одним запросом не получится.
    Как вариант - потом делать пагинацию и фильтрацию полученного результата.

    public function getCategory()
    {
            $queryBuilder = $this->getEntityManager()->createQueryBuilder();
    
            $queryBuilder
            ->select('category')->from($this->getClassName(), 'category')
            ->addSelect('c_categoryHasPosts')->leftJoin('category.categoryHasPosts', 'c_categoryHasPosts')
                ->addSelect('c_cHasP_post')->leftJoin('c_categoryHasPosts.post', 'c_cHasP_post')
                    ->addSelect('c_cHasP_p_postHasComments')->leftJoin('c_cHasP_post.postHasComments', 'c_cHasP_p_postHasComments')
                        ->addSelect('c_cHasP_p_pHasC_comment')->leftJoin('c_cHasP_p_postHasComments.comment', 'c_cHasP_p_pHasC_comment')
            ->setParameter('categoryId', 1)
            ->setParameter('postId', 1)
            ->andWhere('c_cHasP_post.category_id = :categoryId')
            ->orWhere('c_cHasP_p_pHasC_comment.post_id = :postId')
            
            return $queryBuilder->getQuery()->getResult();
    }
    Ответ написан
  • Как можно убрать html теги с базы данных средствами php?

    @novrm
    Реализацию можете подсмотреть в любом фреймворке.
    Например: Zend\Filter\StripTags
    Ответ написан
    Комментировать
  • Какую выбрать схему БД для каталога товаров?

    @novrm
    Вам нужна вот такая схема для БД.

    PMFTUskGQsCLnwYL7hUBTA.jpeg
    Ответ написан
    Комментировать
  • Что нужно возвращать: null или false?

    @novrm
    Странно, конечно, но...
    Методы репозитория должны возвращать сущность или нуль или массив сущностей или пустой массив.
    На то он и репозитории.

    То, что вы пишите true, false или null - должны возвращать сервисы, которые есть посредником между репозиториями и контроллерами.
    Ответ написан
    Комментировать
  • В модели MVC вывод своих страниц ошибок нужно осуществлять через специальный ErrorController?

    @novrm
    403 - это не есть ошибка в коде - это ограничение в правах доступа.
    Как вариант - вы можете просто перенаправить на другую страницу - например на страницу авторизации...
    Для этого нужен только вид, а не контроллер.
    В вики предлагают, еще такой вариант:
    800px-%D0%91%D1%80%D0%B0%D1%83%D0%B7%D0%
    Ответ написан
    Комментировать
  • Есть ли способ удаления лишних закрывающих тегов при парсинге?

    @novrm
    Вам нужно фильтр html-разметки.
    При правильной настройке htmlpurifier - подойдет.
    Ответ написан
    Комментировать
  • Kак добавить пагинацию?

    @novrm
    Чем вам не подошла официальная документация?
    zend-paginator
    Ответ написан
    Комментировать
  • Как Заменить все слэши в ссылках на тире?

    @novrm
    $href = '/privet/vova/love/';
    $result = '/' . implode('_', array_diff(explode('/', $href), [''])); // privet_vova_love
    Ответ написан
    Комментировать
  • Как въехать в программирование (ООП, паттерны)?

    @novrm
    Если вы начали дублировать одинаковый код в проекте - значит вы не до конца поняли ООП и патерны проектирования.
    Избавление от дублирования одинакового кода в проекте - главный мотиватор искать решение в ООП и шаблонах.
    Ответ написан
    4 комментария
  • Как создать личный кабинет?

    @novrm
    Движок для админки - это не bootstrap.
    Из bootstrap вы можете использовать только стиль для админки.
    Мне нравится такой.

    thumbnail.png
    Ответ написан
  • Как грамотно, средствами bootstrap сверстать такой блок?

    @novrm
    Вам нужен компонент Media object.
    Ответ написан
    Комментировать