@UniqueEntity不强制执行多字段约束

时间:2019-05-12 22:45:19

标签: symfony doctrine symfony4

在要求我处理的Symfony 4应用程序中,我试图对给定公司内的程序名称(一种教学课程,而不是软件)实施唯一性约束。尽管尝试了一些限制,但该应用程序还是很高兴让我创建了一个程序,该程序的名称与给定公司中已经存在的程序相同。

我发现了各种关于如何设置复合约束的矛盾示例,并且我通读了许多关于该主题的StackOverflow问题,但无济于事。

与我的实体相关的代码program.php:

<?php

namespace Domain\CoreBundle\Entity;

use Doctrine\ORM\Mapping as ORM;
use Domain\AdminBundle\Service\Helper\RouteListHelper;
use Domain\CoreBundle\Repository\ProgramRepository as ProgramRepo;
use Gedmo\Mapping\Annotation as Gedmo;
use Symfony\Component\Validator\Constraints as Assert;
use Doctrine\Common\Collections\ArrayCollection;
use JsonSerializable;
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;

 /**
  * Program
  * @ORM\Entity(repositoryClass="Domain\CoreBundle\Repository\ProgramRepository")
  * @ORM\Table(name="programs")
  * @UniqueEntity(
  *      fields={"name","company"},
  *      errorPath = "name",
  *      message="A program by that name already exists for this company."
  *      )
  * @ORM\HasLifecycleCallbacks()
  */

class Program implements JsonSerializable
{
    /**
     * @var integer
     *
     * @ORM\Column(name="id", type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    private $id;

    /**
     * @var string
     *
     * @Assert\NotBlank(message="Program Name should not be empty")
     * @ORM\Column(name="name", type="string", length=255)
     */
    private $name;

     /**
     * @ORM\ManyToOne(targetEntity="Company")
     * @ORM\JoinColumn(name="company_id", referencedColumnName="id", nullable=false, onDelete="CASCADE")
     */
    protected $company;

...

和我的addProgramType.php:

<?php

namespace Domain\AdminBundle\Form;

use Domain\CoreBundle\Repository\UserRepository;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Doctrine\ORM\EntityRepository;
use Symfony\Component\Form\Extension\Core\Type\CheckboxType;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;

/**
 * Class AddProgramType
 */
class AddProgramType extends AbstractType
{
    /**
     * @param FormBuilderInterface $builder
     * @param array $options
     */
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $params = array(
            'name' => array(
                'label' => 'Program name:',
                'attr' => array('class' => 'base-box'),
            ),
            'isEnabled' => array(
                'label' => false,
                'attr' => array(
                    'checked' => 'checked',
                ),
            ),
            'isRoiCalculating' => array(
                'label' => false,
            ),
            'duration' => array(
                'label' => 'Duration:',
                'class' => 'DomainCoreBundle:Duration',
                'query_builder' => function (EntityRepository $er) use ($options) {
                    return $er->getDurationsQb($options['company']);
                },
                'choice_label' => 'uniqueName',
                'attr' => array(
                    'class' => 'base-box',
                ),
            ),
            'sessionTypes' => array(
                'class'         => 'DomainCoreBundle:SessionType',
                'query_builder' => function (EntityRepository $er) use($options) {
                    return $er->getAllSessionTypesQb($options['company']);
                },
                'choice_label' => 'name',
                'multiple' => true,
                'label' => 'Session Types:',
                'attr' => array(
                    'class' => 'multiselect-dropdown multiselect-dropdown-session-types',
                    'required' => 'required',
                    'multiple' => 'multiple',
                ),
            ),
            'users' => array(
                'required' => false,
                'class' => 'DomainCoreBundle:User',
                'choices' => $options['userRepo']->findByRoles(
                        array(UserRepository::ROLE_ADMIN,UserRepository::ROLE_COMPANY_ADMIN),
                        $options['company'],
                        false),
                'choice_label' => 'getFullName',
                'multiple' => true,
                'label' => 'Access to admins:',
                'attr' => array(
                    'class' => 'multiselect-dropdown multiselect-dropdown-users',
                    'multiple' => 'multiple',
                ),
            ),
        );

        $builder
            ->add('name', null, $params['name'])
            ->add('isEnabled', CheckboxType::class, $params['isEnabled'])
            ->add('isRoiCalculating', CheckboxType::class, $params['isRoiCalculating'])
            ->add('duration', EntityType::class, $params['duration'])
            ->add('sessionTypes', EntityType::class, $params['sessionTypes'])
            ->add('users', EntityType::class, $params['users']);
    }

    /**
     * @param OptionsResolver $resolver
     */
    public function configureOptions(OptionsResolver $resolver)
    {
        $resolver->setDefaults(array('data_class' => 'Domain\CoreBundle\Entity\Program'));
        $resolver->setRequired(array('company', 'userRepo'));
    }

    /**
     * Return form name
     *
     * @return string
     */
    public function getBlockPrefix()
    {
        return 'add_program';
    }
}

尽管应用程序正确地对名称实施了NotBlank约束,但并没有实施名称+公司的唯一性。

有什么建议吗?

[更新]看起来我在isValid()调用之后成立了公司,感谢BoShurik的接班人。这是显示我的错误的相关控制器代码:

/**
     * Add new program
     *
     * @param Request $request
     *
     * @return Response
     */
    public function addNewAction(Request $request)
    {
        $form = $this->createForm(AddProgramType::class, null, array('company'=>$this->getCurrentCompany(),
                                'userRepo' =>$this->em->getRepository('DomainCoreBundle:User')));

        if ($request->getMethod() === 'POST') {
            $form->handleRequest($request);

            if ($form->isValid()) {
                $company = $this->getCurrentCompany();
                $program = $form->getData();
                $program->setCreatedDate(new \DateTime());
                $program->setCompany($company);
...

2 个答案:

答案 0 :(得分:2)

如果要在数据库级别添加相同的检查,则应在Table()声明中使用@UniqueConstraint批注,并为新索引命名。 像这样:

 /**
  * Program
  * @ORM\Entity(repositoryClass="Domain\CoreBundle\Repository\ProgramRepository")
  * @ORM\Table(name="programs", uniqueConstraints={@ORM\UniqueConstraint(name="IDX_PROGRAM_COMPANY", columns={"name", "company_id"})})
  * @UniqueEntity(
  *      fields={"name","company"},
  *      errorPath = "name",
  *      message="A program by that name already exists for this company."
  *      )
  * @ORM\HasLifecycleCallbacks()
  */

class Program implements JsonSerializable

```

答案 1 :(得分:0)

由于公司字段不是您的表单管理者,因此您需要在表单验证之前设置其值:

# maximum capability of system
user@ubuntu:~$ cat /proc/sys/fs/file-max
708444

# available limit
user@ubuntu:~$ ulimit -n
1024

# To increase the available limit to say 200000
user@ubuntu:~$ sudo vim /etc/sysctl.conf

# add the following line to it
fs.file-max = 200000

# run this to refresh with new config
user@ubuntu:~$ sudo sysctl -p

# edit the following file
user@ubuntu:~$ sudo vim /etc/security/limits.conf

# add following lines to it

* soft  nofile  200000   
* hard  nofile  200000
www-data  soft  nofile  200000
www-data  hard  nofile  200000
root soft nofile 200000   
root hard nofile 200000

# edit the following file
user@ubuntu:~$ sudo vim /etc/pam.d/common-session

# add this line to it
session required pam_limits.so

# logout and login and try the following command
user@ubuntu:~$ ulimit -n
200000

# now you can increase no.of.connections per Nginx worker
# in Nginx main config /etc/nginx/nginx.conf
worker_connections 200000;
worker_rlimit_nofile 200000;