• Как в Symfony 2 раскодить ( decode ) захешированный пароль ( password_hash() )?

    lexxpavlov
    @lexxpavlov
    Программист, преподаватель
    Никак. В том и смысл хэша, что из него невозможно получить изначальный пароль.
    Вам даже брутфорс не поможет, если у вас длина пароля больше 3-5 символов.

    Если вам нужен сам пароль, то есть только одна возможность получить - использовать тогда же, когда был получен от пользователя, то есть, отправлять админу/пользователю в том же запросе, что и пароль пересоздаётся.

    А если пароль нужен позже (например, для функции восстановления пароля), то так не получится - пароль нужно пересоздавать заново.
    Ответ написан
    Комментировать
  • Как проверять данные при использовании RESTFul api в Symfony2?

    lexxpavlov
    @lexxpavlov
    Программист, преподаватель
    Можно сделать фейковые формы, и использовать в них стандартные валидаторы. А можно делать другим способом, более интересным - использовать OptionsResolver - да-да, те самые, которые в формах используются.
    Ответ написан
    Комментировать
  • Подходит ли framework Symfony?

    lexxpavlov
    @lexxpavlov
    Программист, преподаватель
    Мне кажется, что если у вас есть такие вопросы, то вам рано браться за такие проекты.

    А по существу вопроса - берите любой трендовый фреймворк, и не ошибётесь. Берите Symfony2, Zend Framework 2, Yii2, Laravel, Phalcon. Они сопоставимы, разным людям нравятся разные фреймворки.

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

    Symfony требует хорошего знания ООП вообще и php в частности. Другие фреймворки тоже требуют, но симфония особенно.
    Ответ написан
    Комментировать
  • Как добавить существующую сущность в выпадающий список (иконка "+") в SonataAdminBundle?

    lexxpavlov
    @lexxpavlov
    Программист, преподаватель
    Этот список называется add_block. Сам по себе он вроде нигде не прописан, нужно создавать его самостоятельно. На самом деле, я это делал год назад, сейчас работа с этим списком может быть упрощена. Я делал это так (я изменял сонатовский список сущностей, чтобы там выглядело как мне нужно было):
    {# app\Resources\SonataAdminBundle\views\Core\add_block.html.twig #}
    {% block add_block %}
        {% set items_per_column = admin_pool.getOption('dropdown_number_groups_per_colums') %}
        {% set groups = [] %}
    
        {% for group in admin_pool.dashboardgroups %}
            {% set display_group = false %}
    
            {% for admin in group.items if display_group == false %}
                {% if admin.hasRoute('create') and admin.isGranted('CREATE') %}
                    {% set display_group = true %}
                    {% set groups = [group]|merge(groups) %}
                {% endif %}
            {% endfor %}
        {% endfor %}
    
        {% set column_count = (groups|length / items_per_column)|round(0, 'ceil') %}
    
        <div class="dropdown-menu multi-column dropdown-add"
            {% if column_count > 1 %}style="width: {{ column_count*140 }}px;"{% endif %}
                >
            {% for group in groups|reverse %}
                {% set display = (group.roles is empty and is_granted('ROLE_SONATA_ADMIN') ) %}
                {% for role in group.roles if not display %}
                    {% set display = is_granted(role) %}
                {% endfor %}
    
                {% if display %}
    
                    {% if loop.first or loop.index0 % items_per_column == 0 %}
                        {% if loop.first %}
                            <div class="container-fluid">
                                <div class="row">
                        {% else %}
                            </ul>
                        {% endif %}
    
                        <ul class="dropdown-menu{% if column_count > 1 %} col-md-{{ (12/column_count)|round }}{% endif %}">
                    {% endif %}
    
                    {% if loop.index0 % items_per_column != 0 %}
                        <li role="presentation" class="divider"></li>
                    {% endif %}
                    <li role="presentation" class="dropdown-header">{{ group.label|trans({}, group.label_catalogue) }}</li>
    
                    {% for admin in group.items %}
                        {% if admin.hasRoute('create') and admin.isGranted('CREATE') %}
                            <li role="presentation">
                                <a role="menuitem" tabindex="-1" href="{{ admin.generateUrl('create')}}">{{ admin.label|trans({}, admin.translationdomain) }}</a>
                            </li>
                        {% endif %}
                    {% endfor %}
    
                    {% if loop.last %}
                                </ul>
                            </div>
                        </div>
                    {% endif %}
    
                {% endif %}
            {% endfor %}
        </div>
    {% endblock %}


    Там же лежит user_block (который я чаще использую в проектах, чем add_block):
    {# app\Resources\SonataAdminBundle\views\Core\user_block.html.twig #}
    {% block user_block %}
    <li><a href="#"><strong>{{ app.user.name }}</strong></a></li>
    <li><a href="{{ path('fos_user_change_password') }}">Сменить пароль</a></li>
    <li><a href="{{ path('fos_user_security_logout') }}">Выйти</a></li>
    {% endblock %}
    Ответ написан
    2 комментария
  • Symfony2 формы Как вызвать валидатор раньше трансформера?

    lexxpavlov
    @lexxpavlov
    Программист, преподаватель
    Дело в том, что валидация проверяется при обратной трансформации, поэтому, всегда вначале происходит трансформация, а потом только - валидация.

    Вы должны делать валидацию не через стандартные Constraints, напишите свою проверку, и запускайте её через событие, использующее FormEvents::PRE_SUBMIT.

    В этом ответе есть об этом чуть больше инфы.
    Ответ написан
    1 комментарий
  • Почему symfony2 при чистке кеша лезет в базу?

    lexxpavlov
    @lexxpavlov
    Программист, преподаватель
    При запуске консольной команды запускается ядро (kernel), который парсит параметры из config.yml и инициализирует бандлы. Бандл доктрины при этом присоединяется к БД. Можно ли что-то с этим сделать, я не знаю.
    Может, выходом будет сделать свой собственный уровень окружения (environment), в котором не добавлять бандл доктрины, и запускать это окружение при вызове консольной команды.
    Ответ написан
    Комментировать
  • Есть ли в symfony2 бандлы-аналоги Yii2 GridView (см скриншот)?

    lexxpavlov
    @lexxpavlov
    Программист, преподаватель
    Я для сложных таблиц использую jquery-плагин DataTables, мощный плагин с множеством функций. Причём я использую его напрямую, без бандлов (я пока не использовал так много его функций), но есть бандлы, которые включают поддержку DataTables в проект на symfony.
    https://github.com/stwe/DatatablesBundle
    https://github.com/AliHichem/AliDatatableBundle
    Я их не использовал, но на вид они интересные.
    Ответ написан
    Комментировать
  • Как реализовать, закрыть сайт на время в symfony?

    lexxpavlov
    @lexxpavlov
    Программист, преподаватель
    Есть статья, описывающая, как делать Maintenance mode на сайте. С готовыми кодами.

    И есть бандл LexikMaintenanceBundle, который делает это.
    Ответ написан
  • Как сохранить изображение в Symfony при использовании 2ух бандлов?

    lexxpavlov
    @lexxpavlov
    Программист, преподаватель
    Я бы хранил кропленные картинки прямо бандлом ComurImageBundle, без iPHP. ComurImageBundle сам сохранит оригинальный файл (если надо, можно выключить) и обрезанный файл в указанную папку, причём сохранит сам через ajax, ещё до сохранения формы, и в сонату придёт уже готовая строка с уже готовым файлом (обрезанным и оригинальным).
    Убирайте из полей сущности атрибуты, связанные с iPHP и делайте их string вместо array. То есть, делайте прямо как описано в документации бандла ComurImageBundle. А если вам ещё нужно что-то делать ещё и с iPHP, то дополнительно делайте новые поля для iPHP, и сами вручную сохраняйте нужные данные для них в prePersist, как вам советует Денис
    Ответ написан
    Комментировать
  • Битва титанов: BEM vs Twig или твиг уже не то?

    lexxpavlov
    @lexxpavlov
    Программист, преподаватель
    Мне кажется, БЭМ вполне можно использовать в symfony вместе с Twig, а не вместо него. Это в том случае, если БЭМ считать именно как методологию разделения и именования элементов, и не использовать инструменты командной строки. БЭМ не противоречит Twig-у, и Twig не противоречит БЭМу, они о разном. Ведь Twig вообще не занимается управлением CSS.
    Но лично я по БЭМу нормально не делал, для меня БЭМ - это только методология организации CSS. Если он гораздо больше, чем только CSS, то другое дело.

    Использовать БЭМ вместо Twig не получится, ведь в любом случае в шаблон нужно передавать параметры из контроллера. Вот если у вас только REST-сервис, то можно делать без Twig (он там не нужен), но и в этом проекте БЭМ тоже не нужен, он вынесется в другой фронтенд-проект.

    Так что, битва титанов не прошла, как невозможна битва между шахматистом и боксёром.
    Ответ написан
    Комментировать
  • Как в Twig вывести вывод метода класса?

    lexxpavlov
    @lexxpavlov
    Программист, преподаватель
    Запустить статический метод класса можно вызовом через объект этого класса:
    class Test {
        private $x = 10;
    
        public static function getSTatic() {
            return 'static';
        }
        public function getNormal() {
            return 'normal ' . $this->x;
        }
    }

    Теперь в контроллере нужно создать объект этого класса и передать в шаблон:
    {{ test.normal }}
    {{ test.static }}

    В вашем случае можно вызвать вот так: {{ city.nameFromId(salonTables.cityId)) }}, где city - объект класса City.

    Но вообще-то у вас лучше переделать всё полностью. Судя по тегу Symfony в вопросе, вы пользуетесь фреймворком Symfony2. Тогда вам вообще не стоит писать статические методы для получения записей, воспользуйтесь доктриной.
    1) В шаблоне неправильно обращаться к базе данных, правильно подготовить все нужные данные в контроллере и передать их в шаблон:
    class SalonController extends Controller
    {
        /**
         * @Route("/salon/{id}")
         * @Template
         */
        public function salonAction($id)
        {
            $salons = $this->getDoctrine()->getRepository('AppBundle:City')->findBy(array('cityId' => $id));
    
            return array('salons' => $salons);
        }
    }

    2) твиг сам экранирует вывод, делать |escape не обязательно
    3) не стоит добавлять слово table в имя сущности, гораздо лучше писать их вот так:
    {% for salon in salons %}
    { salon.name }}
    {{ salon.cityId }}
    {% endfor %}
    Ответ написан
    Комментировать
  • Symfony 2. Как вывести в форме value selected в списке внедренной формы?

    lexxpavlov
    @lexxpavlov
    Программист, преподаватель
    Похоже, проблема в том, что при создании формы создаётся и новый объект статуса, который не имеет установленного статуса:
    $builder->add( 'status', new formStatusType() )

    Попробуйте передать объект статуса в форму:
    class formEditOldemandType extends AbstractType
    {
        public function buildForm( FormBuilderInterface $builder, array $options )
        {
            $builder->add( 'status', $options['status'] )
            ...
        }
    
        public function getDefaultOptions(array $options)
        {
            return array(
                'data_class' => 'Acme\AppBundle\Entity\Oldemand',
                'status' => new formStatusType(),
            );
        }
    
        public function getName()
        {
            return 'formcloseoldemand';
        }
    }


    У вас старая версия Symfony - метод getDefaultOptions() убран в версии 2.3, и уже в версии 2.1 вместо него используется метод setDefaultOptions(), а в версии 2.7 используется configureOptions(). Вам следовало бы указать этот факт в вопросе. Какая версия использована в вашем проекте?
    Ответ написан
  • Как изменить параметр в Symfony2?

    lexxpavlov
    @lexxpavlov
    Программист, преподаватель
    А где вы пытаетесь установить параметр? и нужно устанавливать в конфигураторе бандла - в классе DependencyInjection\YourBundleExtension. После этого контейнер замораживается, и его изменить нельзя. Если вам это нужно - значит, вы что-то неправильно делаете в архитектуре.
    Если вам нужно изменить параметр на уровне разработки - ставьте нужное значение в parameters.yml (замените Анадырь на Канчалан). А если нужное значение определяется в коде, то его не нужно устанавливать в параметр контейнера, его нужно передавать через аргументы метода сервиса.

    Расскажите подробнее, что у вас за задача, чтобы можно было подробнее подсказать.
    Ответ написан
  • Как правильно реализовать вычисляемое поле для Entity (Symfony/Doctrine)?

    lexxpavlov
    @lexxpavlov
    Программист, преподаватель
    Есть несколько вариантов решения.

    1) грязным хаком получать контейнер и извлекать из него нужные сервисы и параметры. Если нужно решить очень быстро, то можно сделать и так, но тогда потом не забыть прибрать за собой, как появится время на рефакторинг.
    2) сделать фабрику для создания сущности (как вы и говорили)
    Эти два варианта можно посмотреть вот в этом вопросе.

    3) Передать шаблон через параметр метода:
    class User
    {
        // ...
    
        public function getFullDomain($template)
        {
            return str_replace("{subdomain}", $this->subdomain, $template);
        }
    }

    Но код, который использует эту сущность, должен сам получать шаблон, чтобы передать в метод getFullDomain().

    4) Сделать расширение для Twig. Решение в зависимости от назначения этого метода - если полное имя домена выводится только в представлении, то это хороший выход. В приведённой странице документации приведён способ построения фильтра user|fullDomain, но не сложнее сделать и функцию - fullDomain(user), кому что больше нравится.

    5) Сделать сервис, который будет строить полное имя домена. Это самый универсальный способ, ведь во всех остальных случая можно вызвать этот сервис и использовать его метод для построения имени.
    Ответ написан
    1 комментарий
  • Как следить за локализациями в Symfony проектах?

    lexxpavlov
    @lexxpavlov
    Программист, преподаватель
    Для управления переводами есть довольно много решений, как и десктопных (poedit), так и онлайновых (crowdin.net, webtranslateit.com). Подобные программы обычно выдают .mo/.po-файлы, которые можно сконвертировать в xliff, который понимает Symony (кстати, в документации рекомендуется именно xliff).

    А можно поставить LswGettextTranslationBundle, который умеет использовать po-файлы напрямую (в этом вопросе есть кое-какая инфа на этот счёт).
    Ответ написан
    Комментировать
  • Как правильно организовать переходы по ссылкам в Symfony?

    lexxpavlov
    @lexxpavlov
    Программист, преподаватель
    Существует несколько путей:
    1. стандартные ссылки (get-параметры или роуты):

      1.1) через get-параметры: /page?id=123&name=user

      1.2) через роуты с параметрами: /page/user/123 (хуже так: /page/name/user/id/123 или что-то наподобие)
    2. сделать скрытую POST-форму с hidden-данными, и ссылки будут отправлять эту форму
    3. делать js-роутинг. На самом деле, то же самое, что и вариант 2, но больше гибкости
    4. делать ajax-запрос новых страниц, то есть делать одностраничное приложение. Тогда symfony становится rest-бэкендом, а в браузер ставится что-то типа angular
    5. иметь длинные ссылки, но при щелчке на неё сохранять данные в сессию, и делать редирект на более красивую ссылку (что-то подобное делается у phpMyAdmin)
    6. отправлять данные через куки - скриптом ставить данные в куки и переходить на новую страницу, и браузер сам передаст только что записанные данные на сервер.


    Опишите, какие ссылки вы хотите "украсить", может, что-то получится ещё придумать.

    И помните, что все варианты, кроме первого, не позволят нормально поделиться ссылкой - передать ссылку через скайп, или поставить ссылку на другом сайте (реклама), или даже в закладки не поставить. Поэтому, используйте первый способ. К тому же, роуты - это правильный способ делать ссылки в symfony.
    Ответ написан
    2 комментария
  • Как очистить переменную в репозитарии?

    lexxpavlov
    @lexxpavlov
    Программист, преподаватель
    Это в рамках обработки одного запроса? тогда всё понятно, никакое кэширование здесь ни при чём.
    Вы в конструкторе создаёте билдер запросов:
    $this->exist = $this->createQueryBuilder('i')
    То есть, в памяти хранится объект билдера, и в дальнейшем вы обращаетесь несколько раз к этому объекту, который уже имеет своё состояние.
    У вас два подхода:
    1) в каждом методе создавать новый билдер и указывать им нужные общие параметры. Чтобы не дублировать код, можно сделать приватный метод getBuilderExist(), который будет создавать объект билдера и задавать базовые настройки запроса.
    2) либо в методах, использующих уже существующий билдер, клонировать его и использовать копию:
    public function findByCategory($category)
        {
            $qb = clone($this->exist);
            return $qb
                ->andWhere('i.category = :category')
                ->setParameter('category', $category)
                ->getQuery()->getResult();
        }


    Я бы выбрал первый подход, чтобы не добавлять классу лишнее состояние.
    Ответ написан
    5 комментариев
  • Как убрать избыточную информацию из $entity возвращаемой Doctrine2, Symfony?

    lexxpavlov
    @lexxpavlov
    Программист, преподаватель
    Посмотрите на Partial objects.

    Или, если ваша задача позволит, используйте DBAL вместо ORM - вам вернутся только запрошенные данные в виде массива, без связанных объектов (ну, разве вы явно укажете их в SQL). В общем, DBAL - это возможность просто выполнить любой SQL-запрос, без привязки к сущностям.
    Ответ написан
  • Почему не работает document.write во внешнем js файле?

    lexxpavlov
    @lexxpavlov
    Программист, преподаватель
    я тоже сталкивался с этим. Удалённые скрипты должны работать через element.innerHTML, а не через document.write. А так как у меня был не мой скрипт, то я сделал так - я переопределил document.write на свою реализацию, которая как раз и делала element.innerHTML.
    Ответ написан
  • Symfony2. Как сделать элементарный фильтр для формы?

    lexxpavlov
    @lexxpavlov
    Программист, преподаватель
    Я использую jQuery-плагин Datatables. Умеет очень многое, в том числе поможет и в этой задаче.
    Лично я вставлял непосредственно через шаблоны, но вот сейчас увидел, что есть два бандла: stwe/DatatablesBundle и brown298/data-tables-bundle.
    Ответ написан