laravelでdoctrine
はじめに
https://github.com/laravel-doctrine/orm を使ってlaravelでDoctrineしてみた。
インストール
Laravelプロジェクトの作成。
curl -s "https://laravel.build/laravel-doctrine" | bash
cd laravel-doctrine
依存ライブラリのインストール。
sail composer req doctrine/inflector:^1.4 laravel-doctrine/orm laravel-doctrine/migrations
sail artisan vendor:publish --tag="config"
EntityとRepositoryの作成
Entity
larave-doctrine
を使う時はEloquent
のモデルを用いません。代わりにapp/Entities/
以下にモデルの代わりのクラスであるエンティティを作成します。エンティティにはアノテーションでカラム情報などのメタデータを付与する必要がありますが、基本的にはPOPOとして定義できるのがEloquent
との大きな違いです。また、カラムとのマッピングはymlやxmlで定義することもでき、そのようにするとエンティティは純粋なPOPOになります。メタデータに関してはこちらを参照ください。
laravelのレスポンスに直接渡せるようにIlluminate\Contracts\Support\Arrayable
をimplementsしておくと便利です。
<?php
namespace App\Entities;
use Doctrine\ORM\Mapping as ORM;
use Illuminate\Contracts\Support\Arrayable;
/**
* @ORM\Entity
*/
class User implements Arrayable
{
/**
* @ORM\Id
* @ORM\Column(type="integer")
* @ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* @ORM\Column(type="string")
*/
protected $name;
public function getId()
{
return $this->id;
}
public function getName()
{
return $this->name;
}
public function setName($name): self
{
$this->name = $name;
return $this;
}
public function toArray()
{
return [
'id' => $this->id,
'name' => $this->name,
];
}
}
Repository
Doctrineを使った設計では、基本的に一つのエンティティに対して一つのリポジトリを作ります。リポジトリクラスでは以下のようにDoctrine\ORM\EntityRepository
を継承し、コンストラクタで親クラスにEntityManagerInterface
とメタデータを渡します。
また、Doctrine\ORM\EntityRepository
にはfind()
、findAll()
、findBy()
、findOneBy()
、count()
などのよく使うメソッドがあらかじめ定義されているので、これらのメソッドは自分で実装する必要がありません。
<?php
namespace App\Repository;
use App\Entities\User;
use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\EntityRepository;
class UserRepository extends EntityRepository
{
public function __construct(EntityManagerInterface $em)
{
parent::__construct($em, $em->getClassMetadata(User::class));
}
}
マイグレーションの作成と実行
Eloquent
を使う時はマイグレーションファイルは自前で書く必要がありました。Doctrine
では、エンティティに付与したメタデータと実際のDBとの差分を見て自動でマイグレーションを作ってくれます(めちゃくちゃ便利)。
sail artisan doctrine:migrations:diff
sail artisan doctrine:migrations:migrate
簡単な例
コントローラーを作成し、ルートに登録します。
<?php
use App\Http\Controllers\UserController;
use Illuminate\Support\Facades\Route;
Route::group(['auth:api'], function () {
Route::resource('users', UserController::class)->only([
'index', 'store', 'show', 'destroy'
]);;
});
コントローラーの各メソッドでは、先ほど作ったリポジトリをメソッドインジェクションできます。リポジトリにはfindXXX()
系のメソッドが既に定義されているので、簡単な検索ならメソッドを追加するまでもありません。
リポジトリはデータソースとしての役割のみ持っていますので、「データの更新」や「データの削除」などDBへの書き込みはエンティティマネージャーを通して行う必要があります。エンティティマネージャーはlaravel-doctrineでFacadeとして提供されているのでEntityManager::persist($user)
やEntityManager::flush()
のように使うことも可能です。
<?php
namespace App\Http\Controllers;
use App\Entities\User;
use App\Repository\UserRepository;
use Doctrine\ORM\EntityManagerInterface;
use Illuminate\Http\JsonResponse;
class UserController extends Controller
{
public function index(UserRepository $repository): JsonResponse
{
$users = $repository->findAll();
return response()->json(collect($users));
}
public function store(EntityManagerInterface $entityManager): JsonResponse
{
$user = new User();
$user->setName('test');
$entityManager->persist($user);
$entityManager->flush();
return response()->json($user);
}
public function show($id, UserRepository $repository): JsonResponse
{
$user = $repository->find($id);
return response()->json($user);
}
public function destroy($id, UserRepository $repository, EntityManagerInterface $entityManager): JsonResponse
{
$user = $repository->find($id);
if (!$user) {
return response()->json([], 404);
}
$entityManager->remove($user);
$entityManager->flush();
return response()->json();
}
}
こんな感じに動きます。
$ curl http://localhost/api/users
[]
$ curl http://localhost/api/users -X POST
{"id":1,"name":"test"}
$ curl http://localhost/api/users -X POST
{"id":2,"name":"test"}
$ curl http://localhost/api/users -X POST
{"id":3,"name":"test"}
$ curl http://localhost/api/users/2
[{"id":2,"name":"test"}]
$ curl http://localhost/api/users/2 -X DELETE
[]
$ curl http://localhost/api/users
[{"id":1,"name":"test"},{"id":3,"name":"test"}]
感想
Eloquent
を使うメリットはやはりLaravelとの親和性がとても高いところです。しかし、リポジトリパターンを使おうとすると、Eloquent
の便利メソッド系はリポジトリ内でしか使えないという暗黙のルールができてしまいます。それなら最初からリポジトリを考慮した設計のORM使った方がよくない?と思い今回laravel-doctrineを触ってみました。
まだ本当に基本的なことしかしてないですが、ORMとしての機能はまったく問題なさそうな感じがします。また、エンティティにはIlluminate\Contracts\Support\Arrayable
をはじめとするインターフェイス類をimplementsさせればLaravelとの親和性も思ったほど低くならないかも?とも思いました。
もう少し色んなパターンで触ってみます。
続編
Author And Source
この問題について(laravelでdoctrine), 我々は、より多くの情報をここで見つけました https://qiita.com/ggg-mzkr/items/4ef7710272c540fa8c0a著者帰属:元の著者の情報は、元のURLに含まれています。著作権は原作者に属する。
Content is automatically searched and collected through network algorithms . If there is a violation . Please contact us . We will adjust (correct author information ,or delete content ) as soon as possible .