Open5

Spiral Framework の必要情報を雑にまとめる

niisanniisan

ORM周りの実装

エンティティを作る

php app.php create:entity task -f id:primary -f title:string -f content:text -e

これで、ひな型とリポジトリが作成される。

/**
 * @Cycle\Entity(repository="\App\Repository\TaskRepository")
 */
class Task
{
    /**
     * @Cycle\Column(type = "primary")
     */
    public $id;

    /**
     * @Cycle\Column(type = "string")
     */
    public $title;

    /**
     * @Cycle\Column(type = "text")
     */
    public $content;
}

class TaskRepository extends Repository
{
}
niisanniisan

リレーション

リレーションはいろんなやり方がありそうだけど、一応アノテーション使う

<?php
declare(strict_types=1);

namespace App\Database;

use Cycle\Annotated\Annotation as Cycle;
use Cycle\Annotated\Annotation\Relation\BelongsTo;

/**
 * @Cycle\Entity(repository="\App\Repository\CommentRepository")
 */
class Comment
{
    /**
     * @Cycle\Column(type = "primary")
     */
    public $id;

    /**
     * @BelongsTo(target = "Task", nullable=false)
     */
    public $task;

    /**
     * @Cycle\Column(type = "text")
     */
    public $content;
}

これでマイグレーションを作ると外部キーとかも作ってくれる

php app.php cycle:migrate -v
<?php

namespace Migration;

use Spiral\Migrations\Migration;

class OrmDefault7a811cafb53185 extends Migration
{
    protected const DATABASE = 'default';

    public function up(): void
    {
        $this->table('comments')
            ->addColumn('id', 'primary', [
                'nullable' => false,
                'default'  => null
            ])
            ->addColumn('content', 'text', [
                'nullable' => false,
                'default'  => null
            ])
            ->addColumn('task_id', 'integer', [
                'nullable' => false,
                'default'  => null
            ])
            ->addIndex(["task_id"], [
                'name'   => 'comments_index_task_id_60dece74ef2e7',
                'unique' => false
            ])
            ->addForeignKey(["task_id"], 'tasks', ["id"], [
                'name'   => 'comments_foreign_task_id_60dece74ef303',
                'delete' => 'CASCADE',
                'update' => 'CASCADE'
            ])
            ->setPrimaryKeys(["id"])
            ->create();
    }

    public function down(): void
    {
        $this->table('comments')->drop();
    }
}

リレーション含めた保存とかはこんな感じ。

    public function testSaveWithTask()
    {
        $task =  new Task;
        $task->title = 'あいうえお';
        $task->content = 'かきくけこ';

        $comment = new Comment;
        $comment->content = 'たちつてと';
        $comment->task = $task;
        $tr = $this->app->get(TransactionInterface::class);
        $tr->persist($comment);
        $tr->run();

        $orm = $this->app->get(ORM::class);
        $todo = $orm->getRepository(Task::class)->findOne(['title' => $task->title]);
        $comm = $orm->getRepository(Comment::class)->findOne(['content' => $comment->content]);

        $this->assertEquals($task->content, $todo->content);
        $this->assertEquals($comment->content, $comm->content);
    }
}
niisanniisan

HasMany 側のセーブ

こんな感じで行けそう。

Task.php

    /**
     * @HasMany(target = "Comment")
     */
    public $comments;

    public function __construct()
    {
        $this->comments = new ArrayCollection;
    }
    public function testSaveWithComment()
    {
        $task =  new Task;
        $task->title = 'あいうえお';
        $task->content = 'かきくけこ';

        $comment = new Comment;
        $comment->content = 'たちつてと';

        // コメントに追加
        $task->comments->add($comment);
        $tr = $this->app->get(TransactionInterface::class);
        $tr->persist($task);
        $tr->run();

        $orm = $this->app->get(ORM::class);
        $todo = $orm->getRepository(Task::class)->findOne(['title' => $task->title]);
        $comm = $orm->getRepository(Comment::class)->findOne(['content' => $comment->content]);

        $this->assertEquals($task->content, $todo->content);
        $this->assertEquals($comment->content, $comm->content);
    }

どうせならリポジトリに書きたい

niisanniisan

永続化時にIDは足される。

    public function testSaveWithComment()
    {
        //......

        $this->assertEquals($todo->id, $task->id);
        $this->assertEquals($comm->id, $comment->id);
    }
niisanniisan

ManyToMany

これもアノテーションで行ける

<?php
//....
class Battle
{
    //....

    /** @ManyToMany(target = "User", though = "BattleUser") */
    public $users;

    public function __construct()
    {
        $this->users = new PivotedCollection;
    }
}

保存するときは

$battle = new Battle;
$battle->users->add($user1);
$battle->users->add($user2);

/** @var TransactionInterface */
$tr->persist($battle);
$tr->run();

中間テーブルに値を入れたい場合は、

<?php
/**
 * {project-name}
 * 
 * @author {author-name}
 */
declare(strict_types=1);

namespace App\Database;

use Cycle\Annotated\Annotation as Cycle;

/**
 * @Cycle\Entity()
 */
class BattleUser
{

    /**
     * @Cycle\Column(type = "bigPrimary")
     */
    public $id;

    /**
     * @Cycle\Column(type = "boolean")
     */
    public $is_win;

    public function __construct(bool $is_win)
    {
        $this->is_win = $is_win;
    }
}

のように定義しておいて、

$battle = new Battle;
$battle->users->add($user1);
$battle->users->setPivot($user1, new BattleUser(true));
$battle->users->add($user2);
$battle->users->setPivot($user2, new BattleUser(false));

/** @var TransactionInterface */
$tr->persist($battle);
$tr->run();

これで行ける。