LoginSignup
3
3

More than 3 years have passed since last update.

laravel-doctrine でDBからgetter, setter付きクラスの自動生成する

Last updated at Posted at 2019-06-03

経緯

ServiceとRepository間でデータのやり取りをする際に、型付きのオブジェクトを使うため、SymfonyのORMライブラリdoctrineを基にしたlaravelのライブラリである「laravel-doctrine/orm」を使用して、DBのスキーマから直接クラスをgetter, setter付きで自動生成する、というのを試してみました。

前提条件

Laravel5.8
laravel-doctrine/orm 1.4
MySQL8.*
laravel-doctrine/ormは開発で自動コード生成にのみ使用します。実際のDB操作には使用しない想定です。

1 laravel-doctrineの取得

composer require laravel-doctrine/orm --dev

2 config/doctrine.phpの生成、修正

php artisan vendor:publish --tag="config"

[出力]
Copied File [/vendor/laravel-doctrine/orm/config/doctrine.php] To [/config/doctrine.php]
Publishing complete.

下記のようにconfig/doctrine.phpを修正します。

'managers'                   => [
        'default' => [
            'dev'           => env('APP_DEBUG', false),
            'meta'          => env('DOCTRINE_METADATA', 'annotations'),
            'connection'    => env('DB_CONNECTION', 'mysql'),
            'namespaces'    => ['App\Mappings'],
            'paths'         => [
                base_path('app/Mappings')
            ],
            'repository'    => Doctrine\ORM\EntityRepository::class,
            'proxies'       => [
                'namespace'     => false,
                'path'          => storage_path('proxies'),
                'auto_generate' => env('DOCTRINE_PROXY_AUTOGENERATE', false)
            ],

3 PrimaryKeyがないテーブルに対するエラー の回避

TableにPrimaryKeyが無いと、次のコマンドでDatabaseからマッピングのクラスをインポートする際に、下記のエラー が出る。

Doctrine\ORM\Mapping\MappingException : Table change_reason_master has no primary key. Doctrine does not support reverse engineering from tables that don't have a primary key.

これを避けるため、vendor\doctrine\orm\lib\Doctrine\ORM\Mapping\Driver\DatabaseDriver.phpを置き換えると自動生成が動くようでした。
(コードを生成後は元のコードに戻しておく、との記述がありました)

参照:https://medium.com/@joaoneto/solves-doctrine-orm-error-with-tables-without-primary-key-on-mysql-when-mapping-the-database-1ce740610b51

 //~~~~
           if ( ! $table->hasPrimaryKey()) {

                // throw new MappingException(
                //     "Table " . $table->getName() . " has no primary key. Doctrine does not ".
                //     "support reverse engineering from tables that don't have a primary key."
                // );


            }


            // $pkColumns = $table->getPrimaryKey()->getColumns();

            //ADD ↓↓↓
            $pkColumns = $table->hasPrimaryKey()? $table->getPrimaryKey()->getColumns() : [];
            //ADD ↑↑↑

//~~~~

    private function getTablePrimaryKeys(Table $table)
    {
        try {
            //DELETE ↓↓↓
            // return $table->getPrimaryKey()->getColumns();
            //DELETE ↑↑↑

            //ADD ↓↓↓
            if($table->hasPrimaryKey()){
                return $table->getPrimaryKey()->getColumns();
            }
            //ADD ↑↑↑

        } catch (SchemaException $e) {
            // Do nothing
        }

        return [];
    }

4 マッピングの作成

php artisan doctrine:mapping:import annotation

→app\Mapping直下にテーブルのEntityの元データ(getter, setterのメソッド無し)が作成される。
(これでもクラスとしては使用できるが全てprivate のプロパティのみのクラスとなってしまう。)

5 getter, setter付きクラスの生成

php artisan doctrine:generate:entities --generate-annotations --generate-methods

→app\Entities直下にテーブルのEntityの元データ(getter, setterのメソッド付き)が作成される
 (app\Mappingにあるphpファイルを元に生成される)

生成されたUsersクラス

<?php



use Doctrine\ORM\Mapping as ORM;

/**
 * Users
 *
 * @ORM\Table(name="users")
 * @ORM\Entity
 */
class Users
{
    /**
     * @var int
     *
     * @ORM\Column(name="id", type="integer", precision=0, scale=0, nullable=false, options={"unsigned"=true}, unique=false)
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="IDENTITY")
     */
    private $id;

    /**
     * @var string
     *
     * @ORM\Column(name="name", type="string", length=50, precision=0, scale=0, nullable=false, unique=false)
     */
    private $name;

    /**
     * @var string
     *
     * @ORM\Column(name="email", type="string", length=50, precision=0, scale=0, nullable=false, unique=false)
     */
    private $email;

    /**
     * @var \DateTime|null
     *
     * @ORM\Column(name="email_verified_at", type="datetime", precision=0, scale=0, nullable=true, unique=false)
     */
    private $emailVerifiedAt;

    /**
     * @var string|null
     *
     * @ORM\Column(name="password", type="string", length=100, precision=0, scale=0, nullable=true, unique=false)
     */
    private $password;

    /**
     * @var string|null
     *
     * @ORM\Column(name="remember_token", type="string", length=100, precision=0, scale=0, nullable=true, unique=false)
     */
    private $rememberToken;

    /**
     * @var \DateTime|null
     *
     * @ORM\Column(name="created_at", type="datetime", precision=0, scale=0, nullable=true, unique=false)
     */
    private $createdAt;

    /**
     * @var \DateTime|null
     *
     * @ORM\Column(name="updated_at", type="datetime", precision=0, scale=0, nullable=true, unique=false)
     */
    private $updatedAt;


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

    /**
     * Set name.
     *
     * @param string $name
     *
     * @return Users
     */
    public function setName($name)
    {
        $this->name = $name;

        return $this;
    }

    /**
     * Get name.
     *
     * @return string
     */
    public function getName()
    {
        return $this->name;
    }

    /**
     * Set email.
     *
     * @param string $email
     *
     * @return Users
     */
    public function setEmail($email)
    {
        $this->email = $email;

        return $this;
    }

    /**
     * Get email.
     *
     * @return string
     */
    public function getEmail()
    {
        return $this->email;
    }

    /**
     * Set emailVerifiedAt.
     *
     * @param \DateTime|null $emailVerifiedAt
     *
     * @return Users
     */
    public function setEmailVerifiedAt($emailVerifiedAt = null)
    {
        $this->emailVerifiedAt = $emailVerifiedAt;

        return $this;
    }

    /**
     * Get emailVerifiedAt.
     *
     * @return \DateTime|null
     */
    public function getEmailVerifiedAt()
    {
        return $this->emailVerifiedAt;
    }

    /**
     * Set password.
     *
     * @param string|null $password
     *
     * @return Users
     */
    public function setPassword($password = null)
    {
        $this->password = $password;

        return $this;
    }

    /**
     * Get password.
     *
     * @return string|null
     */
    public function getPassword()
    {
        return $this->password;
    }

    /**
     * Set rememberToken.
     *
     * @param string|null $rememberToken
     *
     * @return Users
     */
    public function setRememberToken($rememberToken = null)
    {
        $this->rememberToken = $rememberToken;

        return $this;
    }

    /**
     * Get rememberToken.
     *
     * @return string|null
     */
    public function getRememberToken()
    {
        return $this->rememberToken;
    }

    /**
     * Set createdAt.
     *
     * @param \DateTime|null $createdAt
     *
     * @return Users
     */
    public function setCreatedAt($createdAt = null)
    {
        $this->createdAt = $createdAt;

        return $this;
    }

    /**
     * Get createdAt.
     *
     * @return \DateTime|null
     */
    public function getCreatedAt()
    {
        return $this->createdAt;
    }

    /**
     * Set updatedAt.
     *
     * @param \DateTime|null $updatedAt
     *
     * @return Users
     */
    public function setUpdatedAt($updatedAt = null)
    {
        $this->updatedAt = $updatedAt;

        return $this;
    }

    /**
     * Get updatedAt.
     *
     * @return \DateTime|null
     */
    public function getUpdatedAt()
    {
        return $this->updatedAt;
    }
}

自動生成した際には、上書きしてしまうため、
自動生成後に別のディレクトリに移して
スキーマの変更があった時にはそのスキーマのクラスの変更部分のみ更新するのが良いかもしれません。

以上です。

3
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
3