doctrine – Блог Stafox'a https://stafox.cc О программировании и веб-разработке Sun, 20 Mar 2016 20:35:20 +0000 en-US hourly 1 https://wordpress.org/?v=5.8.2 Warning: Erroneous data format for unserializing ‘App\UserBundle\Entity\User’ https://stafox.cc/warning-erroneous-data-format-for-unserializing-app-userbundle-entity-user/ https://stafox.cc/warning-erroneous-data-format-for-unserializing-app-userbundle-entity-user/#comments Sun, 20 Mar 2016 20:35:20 +0000 http://stafox.ru/?p=2776 Ошибка Doctrine 2 с FOS\UserBundle. Воспроизводится на PHP 5.6 при использовании FOS/UserBundle для Symfony и старой версии доктрины 2.3.х. Лог такой: Warning: Erroneous data format for unserializing 'App\UserBundle\Entity\User' in project/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/ClassMetadataInfo.php Я нашел два способа исправления. Обновить версию Doctrine Обновить Doctrine до версии 2.4.x или выше. Однако не всегда это допустимо, в силу того, что что-нибудь

Сообщение Warning: Erroneous data format for unserializing ‘App\UserBundle\Entity\User’ появились сначала на Блог Stafox'a.

]]>
Ошибка Doctrine 2 с FOS\UserBundle. Воспроизводится на PHP 5.6 при использовании FOS/UserBundle для Symfony и старой версии доктрины 2.3.х.

Лог такой:


Warning: Erroneous data format for unserializing 'App\UserBundle\Entity\User' in project/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/ClassMetadataInfo.php

Я нашел два способа исправления.

Обновить версию Doctrine

Обновить Doctrine до версии 2.4.x или выше. Однако не всегда это допустимо, в силу того, что что-нибудь может отвалиться. А исправить нужно здесь и сейчас 🙂

Изменить способ создания объекта без конструктора

Собственно причина проблемы – это способ, который использует Doctrine для создания объекта без вызова конструктора – десериализация данных.
Можно исправить метод newInstance() и создавать объект через рефлексию.


function newInstance()
{
    if ($this->_prototype === null) {
        if (method_exists($this->reflClass, 'newInstanceWithoutConstructor')) {
            $this->_prototype = $this->reflClass->newInstanceWithoutConstructor();
        } else {
            $this->_prototype = unserialize(sprintf('O:%d:"%s":0:{}', strlen($this->name), $this->name));
        }
    }

    return clone $this->_prototype;
}

Сообщение Warning: Erroneous data format for unserializing ‘App\UserBundle\Entity\User’ появились сначала на Блог Stafox'a.

]]>
https://stafox.cc/warning-erroneous-data-format-for-unserializing-app-userbundle-entity-user/feed/ 1
Столбец в качестве ключа для результирующей выборки в Doctrine 2 https://stafox.cc/define-column-as-key-for-result-array-in-doctrine-2/ https://stafox.cc/define-column-as-key-for-result-array-in-doctrine-2/#respond Thu, 08 Oct 2015 06:02:23 +0000 http://stafox.ru/?p=2664 Вернуть в качестве ключа выборки значение одного из столбцов – довольно частая задача. Достичь результата можно несколькими способами. INDEX BY createQuery() Если Вы создаете запрос используя createQuery, то достаточно добавить к конструкции FROM конструкцию INDEX BY column_name. namespace DemoBundle\Repository; use Doctrine\ORM\EntityRepository; class SettingsRepository extends EntityRepository { public function getSettingsIndexedByName() { $query = $this->createQuery('SELECT s FROM

Сообщение Столбец в качестве ключа для результирующей выборки в Doctrine 2 появились сначала на Блог Stafox'a.

]]>
Вернуть в качестве ключа выборки значение одного из столбцов – довольно частая задача. Достичь результата можно несколькими способами.

INDEX BY

createQuery()
Если Вы создаете запрос используя createQuery, то достаточно добавить к конструкции FROM конструкцию INDEX BY column_name.


namespace DemoBundle\Repository;

use Doctrine\ORM\EntityRepository;

class SettingsRepository extends EntityRepository
{
    public function getSettingsIndexedByName()
    {
        $query = $this->createQuery('SELECT s FROM DemoBundle:Settings s INDEX BY s.name');
        return $query->getResult();
    }
}

createQueryBuilder()
Но Вы наверняка используете QueryBuilder для создания запросов, он также позволяет использовать indexBy. Метод createQueryBuilder принимает два параметра: alias и indexBy.


namespace DemoBundle\Repository;

use Doctrine\ORM\EntityRepository;

class SettingsRepository extends EntityRepository
{
    public function getSettingsIndexedByName()
    {
        $qb = $this->createQueryBuilder('s', 's.name')
            ->select('s');
        $query = $qb->getQuery();
        return $query->getResult();
    }
}

Однако в предыдущих версиях Doctrine (например 2.4.7) метод createQueryBuilder выглядит следующим образом.


public function createQueryBuilder($alias)
{
    return $this->_em->createQueryBuilder()
        ->select($alias)
        ->from($this->_entityName, $alias);
}

Как видите, нет параметра indexBy. Решить эту проблему можно расширив класс Doctrine\ORM\EntityRepository.


namespace DemoBundle\Repository;

use Doctrine\ORM\EntityRepository as DoctrineEntityRepository;

class EntityRepository extends DoctrineEntityRepository
{
    public function createQueryBuilder($alias, $indexBy = null)
    {
        return $this->_em->createQueryBuilder()
            ->select($alias)
            ->from($this->_entityName, $alias, $indexBy);
    }
}

Теперь Вам нужно только унаследовать от него свои классы-репозитории и воспользоваться переопределенным методом createQueryBuilder()

Hydrators

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

Сообщение Столбец в качестве ключа для результирующей выборки в Doctrine 2 появились сначала на Блог Stafox'a.

]]>
https://stafox.cc/define-column-as-key-for-result-array-in-doctrine-2/feed/ 0
Symfony 2: UniqueEntity и валидация формы https://stafox.cc/symfony-2-uniqueentity-and-form-validation/ https://stafox.cc/symfony-2-uniqueentity-and-form-validation/#respond Sun, 30 Aug 2015 10:53:29 +0000 http://stafox.ru/?p=2642 Есть стандартная задача, с которой наверняка сталкивался каждый веб-разработчик: при добавлении сущности в БД убедиться, что такой еще нет, а если есть, то отобразить соответствующее сообщение. Хочу поделиться реализацией такой задачи в Symfony 2. Конкретный пример: необходимо реализовать функционал подписки на разные почтовые рассылки. Есть несколько вариантов как это можно сделать: можно повесить уникальный индекс

Сообщение Symfony 2: UniqueEntity и валидация формы появились сначала на Блог Stafox'a.

]]>
Есть стандартная задача, с которой наверняка сталкивался каждый веб-разработчик: при добавлении сущности в БД убедиться, что такой еще нет, а если есть, то отобразить соответствующее сообщение. Хочу поделиться реализацией такой задачи в Symfony 2.

Конкретный пример: необходимо реализовать функционал подписки на разные почтовые рассылки.

Есть несколько вариантов как это можно сделать:

  • можно повесить уникальный индекс на поля в таблице и отлавливать определенную ошибку c кодом 23000.
  • можно предварительно делать выборку на наличие такой записи в таблице.

В случае с Doctrine второй вариант предпочтительнее, т.к. в первом случае, при возникновении ошибки Doctrine рвет соединение с БД. Я расскажу о том, как сделать это автоматически при помощи компонентов Symfony.

У нас имеются сущности Newsletter (рассылка) и Subscriber (подписчик).


SubscribeBundle\Entity\Newsletter:
    type: entity
    table: newsletter
    fields:
        id:
            type: integer
            id: true
            generator:
                strategy: AUTO
        title:
            type: string
            length: 255
    lifecycleCallbacks: {  }


SubscribeBundle\Entity\Subscriber:
    type: entity
    table: subscriber
    fields:
        id:
            type: integer
            id: true
            generator:
                strategy: AUTO
        newsletterId:
            type: integer
            column: newsletter_id
        email:
            type: string
            length: 255
    lifecycleCallbacks: {  }
    manyToOne:
        newsletter:
            targetEntity: Newsletter
            joinColumn:
                name: newsletter_id
                referencedColumnName: id
            cascade: ["persist"]
    uniqueConstraints:
        newsletter_subscriber:
            columns: [ newsletter_id, email ]

Нам понадобится компонент Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity. Для того, чтобы воспользоваться им, необходимо добавить в src/SubscribeBundle/Resources/config/validation.yml следующее:


SubscribeBundle\Entity\Subscriber:
    constraints:
        - Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity:
            fields: [newsletterId, email]
            errorPath: email
            message: 'You already subscribed to this newsletter'

fields – параметр, который указывает на какие поля распространяется условие уникальности.
errorPath – параметр, который указывает на какое поле повесить ошибку (по умолчанию первое поле из параметра fields)
message – сообщение, которое будет показано при нарушении уникальности.

Создадим форму и передадим ей сущность Subscriber.


$subscriber = new \SubscribeBundle\Entity\Subscriber();
$form = $this->createFormBuilder($subscriber , ['attr' => ['id' => 'subscribe_form']])
    ->setAction($this->generateUrl('subscribe'))
    ->add('email', 'email', [
        'constraints' => [new NotBlank(), new Email()],
        'attr' => ['placeholder' => 'Enter your e-mail address...']
    ])
    ->add('newsletter_id', 'hidden', [
        'constraints' => new NotBlank(),
        'data' => 1 // NewsletterId should be here
    ])
    ->add('subscribe', 'submit', [
        'label' => 'Subscribe'
    ])
    ->getForm();

Теперь при валидации формы будет происходить проверка на уникальность почтового адреса для определенной рассылки.


...
$form->handleRequest($request);

if ($form->isValid()) {
    // Save entity to database
} else {
    $errors = $this->getErrorMessages($form);
    // Display somewhere received errors
}

Ну вот в принципе и всё. Для наглядности постараюсь в ближайшее время поделиться бандлом Subscribe.

Сообщение Symfony 2: UniqueEntity и валидация формы появились сначала на Блог Stafox'a.

]]>
https://stafox.cc/symfony-2-uniqueentity-and-form-validation/feed/ 0