Doctrine2具有多个字段的唯一验证

时间:2014-03-15 13:18:47

标签: php validation doctrine-orm zend-framework2

我有一个实体Booking,它与User有多对一的关系。 每个Booking实体都有一个date字段,对用户来说应该是唯一的。

例如,条目可能如下所示:

+----------+---------+
|   date   | user_id |
+----------+---------+
| 12-04-88 |       1 |
| 13-04-88 |       1 |
| 12-04-88 |       2 |
+----------+---------+

但不是这样的:

+----------+---------+
|   date   | user_id |
+----------+---------+
| 12-04-88 |       1 |
| 12-04-88 |       1 |
+----------+---------+

使用ZF2 REST控制器添加Booking实体的代码如下:

输入过滤器

class BookingFilter extends InputFilter
{

    //TODO: Get from module config
    protected $config = array(
        'date-format'   => 'd-m-Y',
        'start-min'     => '07:00',
        'start-max'     => '10:00',
        'end-min'       => '16:00',
        'end-max'       => '19:00',
        'step'          => '900', //15 x 60 - 15 Min's
    );

    public function init()
    {

        $this->add(
            array(
                'name'      => 'date',
                'required'  => true,
                'validators' => array(
                    array(
                        'name'      => 'Date',
                        'options'   => array(
                            'format' => 'd-m-Y',
                        ),
                    ),
                ),
            )
        );

        $this->add(
            array(
                'name'      => 'startTime',
                'required'  => true,
                'filters'   => array(
                    array('name' => 'StringTrim')
                ),
                'validators' => array(
                    array(
                        'name'      => 'Date',
                        'options'   => array(
                            'format' => 'H:i',
                        ),
                    ),
                    array(
                        'name'      => 'GreaterThan',
                        'options'   => array(
                            'min'       => $this->config['start-min'],
                            'inclusive' => true,
                        ),
                    ),
                    array(
                        'name'      => 'LessThan',
                        'options'   => array(
                            'max'       => $this->config['start-max'],
                            'inclusive' => true,
                        ),
                    ),
                    array(
                        'name'      => 'DateStep',
                        'options'   => array(
                            'format'    => 'H:i',
                            'baseValue' => $this->config['start-min'],
                            'step'      => new \DateInterval("PT{$this->config['step']}S"),
                        ),
                    ),

                ),
            )
        );

        $this->add(
            array(
                'name'      => 'endTime',
                'required'  => true,
                'filters'   => array(
                    array('name' => 'StringTrim')
                ),
                'validators' => array(
                    array(
                        'name'      => 'Date',
                        'options'   => array(
                            'format' => 'H:i',
                        ),
                    ),
                    array(
                        'name'      => 'GreaterThan',
                        'options'   => array(
                            'min'       => $this->config['end-min'],
                            'inclusive' => true,
                        ),
                    ),
                    array(
                        'name'      => 'LessThan',
                        'options'   => array(
                            'max'       => $this->config['end-max'],
                            'inclusive' => true,
                        ),
                    ),
                    array(
                        'name'      => 'DateStep',
                        'options'   => array(
                            'format'    => 'H:i',
                            'baseValue' => $this->config['end-min'],
                            'step'      => new \DateInterval("PT{$this->config['step']}S"),
                        ),
                    ),

                ),
            )
        );

        //notes
        $this->add(
            array(
                'name'      => 'notes',
                'required'  => false,
                'filters'   => array(
                    array('name' => 'StripTags'),
                    array('name' => 'StringTrim')
                ),
                'validators' => array(
                    array(
                        'name'    => 'StringLength',
                        'options' => array(
                            'encoding' => 'UTF-8',
                            'min'      => 1,
                            'max'      => 512,
                        ),
                    ),
                ),
            )
        );
    }
} 

控制器操作

public function create($data)
{

    $user    = $this->zfcUserAuthentication()->getIdentity();
    $booking = $this->getTimeBookingService()->validateBooking($data, $user);

    $booking->setUser($user);
    //some other stuff
    //persist
}

服务

public function validateBooking(array $data, UserInterface $user, Booking $booking = null)
{
    $filter = $this->getInputFilter();
    $filter->setData($data);

    if (!$filter->isValid()) {
        $this->messages = $filter->getMessages();
        return false;
    }

    if (!$booking) {
        $booking = new Booking;
    }
    $this->getDoctrineHydrator()->hydrate($filter->getValues(), $booking);

    //if this is a new booking - not an update
    if (!$booking->getId()) {
        $row = $this->bookingRepository->findOneBy(array('date' => $booking->getDate(), 'user' => $user));
        if (is_object($row)) {
            //user already has booking for this date
            $this->messages['date'] = array('This user already has a booking for this date');
            return false;
        }
    }

    return $booking;
}

问题

如何使用默认的Doctrine Validator或自定义Doctrine / ZF2验证器?

我不喜欢我的方法,似乎我复制了Validator组件的工作,但是,我上次尝试时无法使用Doctrine Unique Validator,因为那里超过1个字段需要是唯一的。

我正在考虑扩展Doctrine Unique验证器,它依赖于User,它将注入一个构造,然后扩展validate方法以使用dateuser来搜索存储库。 {{1}}字段?

1 个答案:

答案 0 :(得分:1)

  

我正在考虑用一个扩展Doctrine Unique验证器   对用户的依赖将被注入一个构造然后   扩展validate方法以使用两个日期搜索存储库   和用户字段?

向模型添加一些更改,您可以将dateuser_id主键设置在一起:

/** @Id @Column(type="integer") */
private $id;
/** @Id @Column(type="date") */
private $date;

我不知道你的框架控制器如何持久保存该对象,但你可以这样做:

try
{
   $booking = new Booking(1, '12-19-2000');
   em->persist($booking);
   em->flush();
}
catch( \Doctrine\DBAL\DBALException $e )
{ 
    /* the error 23000 should print the unique constrains mysql error */
    if( $e->getPrevious()->getCode() === '23000' ) 
    { 
        echo "entity already exists";
    }
}