Symfony 4 + Doctrine:组织子文件夹中的实体

时间:2018-03-30 11:21:04

标签: php symfony doctrine-orm

我试图用Symfony 4和Doctrine创建一个网站。我是一个完整的初学者(一般都是Symfony和PHP),所以如果我的问题很简单,我会道歉。

我想用doctrine创建一个数据库,这意味着我必须在src/Entity中创建类。但我也希望向网站添加表单,并且还需要src/Entity中的类。我想在两个子文件夹中分隔这些类:src/Entity/databasesrc/Entity/forms。我尝试按如下方式编辑config/packages/doctrine.yaml

doctrine:
    #...
    orm:
        #...
        mappings:
            App:
                #...
                dir: '%kernel.project_dir%/src/Entity/database'
                prefix: 'App\Entity\database'

但是,当我使用bin/console make:entity Entity时,它会在src/Entity中创建文件并出现以下错误:

[ERROR] Only annotation mapping is supported by make:entity, but the
    <info>App\Entity\Entity</info> class uses a different format. If you
    would like this command to generate the properties & getter/setter
    methods, add your mapping configuration, and then re-run this command
    with the <info>--regenerate</info> flag.

当我运行bin/console make:entity Entity --regenerate时,它说:

[ERROR] No entities were found in the "Entity" namespace.

我也试过bin/console make:entity database/Entity,但它失败了:

 [ERROR] "App\Entity\Database/Entity" is not valid as a PHP class name (it must start with a letter or underscore,
     followed by any number of letters, numbers, or underscores)

如果我使用反斜杠(database\Entity)执行相同操作,则会在错误的目录中创建一个DatabaseEntity.php文件,并提供与第一个相同的错误。

1 个答案:

答案 0 :(得分:1)

要非常小心,因为采用这种方法可能会破坏您的架构。这个问题有点自以为是,但我会告诉你我们是如何用实体和形式来做的。

首先,我坚信,实体和表格应该是分开的。因此,我们在src/Entity中包含了Entites,在src/Form中包含了Form。它们之间的连接是FormType,我们包含src/FormType中的那些。

以下是src/Entity/User.php中包含的用户实体示例:

namespace App\Entity;

use Doctrine\ORM\Mapping as ORM;
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
use Symfony\Component\Security\Core\User\UserInterface;
use Symfony\Component\Validator\Constraints as Assert;

/**
 * @UniqueEntity("username")
 *
 * @ORM\Entity()
 * @ORM\Table(name="users")
 */
class User implements UserInterface, \Serializable
{
    /**
     * @ORM\Column(type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     *
     * @var int
     */
    private $id;


    /**
     * @Assert\NotBlank()
     * @Assert\Email
     * @Assert\Length(max="255")
     *
     * @ORM\Column(type="string", length=255, unique=true)
     *
     * @var string
     */
    private $username;


    /**
     * @ORM\Column(type="string", length=64)
     *
     * @var string
     */
    private $password;

    /**
     * @return int
     */
    public function getId(): int
    {
        return $this->id;
    }


    /**
     * @return string The username
     */
    public function getUsername()
    {
        return $this->username;
    }


    /**
     * @param null|string $username
     *
     * @return User
     */
    public function setUsername(?string $username): User
    {
        $this->username = (string) $username;

        return $this;
    }


    /**
     * @return string
     */
    public function getPassword(): string
    {
        return $this->password;
    }


    /**
     * @param null|string $password
     *
     * @return User
     */
    public function setPassword(?string $password): User
    {
        $this->password = (string) $password;

        return $this;
    }
}

现在,我们需要一个用户才能注册。为此,我们创建一个FormType和一个Form。看看src/FormType/User.php

namespace App\FormType;

use App\Entity;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type as NativeType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Validator\Constraints\NotBlank;

class User extends AbstractType
{
    public function getParent(): string
    {
        return BaseType::class;
    }


    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        // This maps `Entity\User::username` to the respective field
        $builder->add(
            'username',
            NativeType\EmailType::class,
            ['label' => 'username']
        );

        // This maps `Entity\User::password` to the respective field    
        $builder->add(
            'password',
            NativeType\RepeatedType::class,
            [
                'constraints' => [new NotBlank()],
                'invalid_message' => 'nonMatchingPasswords',
                'first_options' => ['label' => 'password'],
                'second_options' => ['label' => 'password again'],
                'type' => NativeType\PasswordType::class,
            ]
        );
    }

    // This tells Symfony to resolve the form to the `Entity\User` class
    public function configureOptions(OptionsResolver $resolver)
    {
        $resolver->setDefaults(['data_class' => Entity\User::class]);
    }
}

现在表格本身就是src/Form/UserRegistration.php

namespace App\Form;

use App\FormType;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type as NativeType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Validator\Constraints;

class UserRegistration extends AbstractType
{
    public function getParent()
    {
        // Note this!
        return FormType\User::class;
    }


    public function configureOptions(OptionsResolver $resolver)
    {
        $resolver->setDefaults(
            [
                'fields' => ['username', 'password'],
                'translation_domain' => 'forms',
            ]
        );
    }
}

最后一击。在src/Controller/Registration.php我们这样做:

$form = $this->createForm(
    Form\UserRegistration::class,
    $user = new Entity\User()
);

其他(如何处理表格等)你知道。如果你不这样做,请阅读Symfony文档,它们完全覆盖它。

我已经从这个例子中删除/编辑了一些敏感或非必要的东西。例如,我们不将password绑定到password,我们要求输入普通密码然后对其进行加密。我没有测试过上面的内容,所以它可能不稳定。但是为了演示你的架构应该如何完成,这是一个很好的例子,IMO。