Skip to content

Instantly share code, notes, and snippets.

@carousel
Created March 5, 2018 20:54

Revisions

  1. carousel created this gist Mar 5, 2018.
    202 changes: 202 additions & 0 deletions hexagon.php
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,202 @@
    <?php

    interface ReadPostRepository
    {
    public function byId(PostId $id);
    public function all();
    public function byCategory(CategoryId $categoryId);
    public function byTag(TagId $tagId);
    public function withComments(PostId $id);
    public function groupedByMonth();
    }

    interface WritePostRepository
    {
    public function byId(PostId $id);
    public function add(Post $post);
    }

    //MySQL repository implementation
    class PDOPostRepository implements WritePostRepository
    {
    private $db;
    public function __construct(PDO $db)
    {
    $this->db = $db;
    }
    public function byId(PostId $id)
    {
    $stm = $this->db->prepare(
    'SELECT * FROM posts WHERE id = ?'
    );
    $stm->execute([$id->id()]);
    return recreateFrom($stm->fetch());
    }
    public function add(Post $post)
    {
    $stm = $this->db->prepare(
    'INSERT INTO posts (title, content) VALUES (?, ?)'
    );
    $stm->execute([
    $post->title(),
    $post->content(),
    ]);
    }
    }

    class AggregateRoot
    {
    private $recordedEvents = [];

    protected function recordApplyAndPublishThat(DomainEvent $domainEve
    {
    $this->recordThat($domainEvent);
    $this->applyThat($domainEvent);
    $this->publishThat($domainEvent);
    }

    protected function recordThat(DomainEvent $domainEvent)
    {
    $this->recordedEvents[] = $domainEvent;
    }

    protected function applyThat(DomainEvent $domainEvent)
    {
    $modifier = 'apply' . get_class($domainEvent);
    $this->$modifier($domainEvent);
    }

    protected function publishThat(DomainEvent $domainEvent)
    {
    DomainEventPublisher::getInstance()->publish($domainEvent);
    }

    public function recordedEvents()
    {
    return $this->recordedEvents;
    }

    public function clearEvents()
    {
    $this->recordedEvents = [];
    }
    }

    //Post aggregate (with events)
    class Post extends AggregateRoot
    {
    private $id;
    private $title;
    private $content;
    private $published = false;
    private $categories;

    private function __construct(PostId $id)
    {
    $this->id = $id;
    $this->categories = new Collection();
    }

    public static function writeNewFrom($title, $content)
    {
    $postId = PostId::create();
    $post = new static($postId);
    $post->recordApplyAndPublishThat(
    new PostWasCreated($postId, $title, $content)
    );
    }

    public function publish()
    {
    $this->recordApplyAndPublishThat(
    new PostWasPublished($this->id)
    );
    }

    public function categorizeIn(CategoryId $categoryId)
    {
    $this->recordApplyAndPublishThat(
    new PostWasCategorized($this->id, $categoryId)
    );
    }

    public function changeContentFor($newContent)
    {
    $this->recordApplyAndPublishThat(
    new PostContentWasChanged($this->id, $newContent)
    );
    }

    public function changeTitleFor($newTitle)
    {
    $this->recordApplyAndPublishThat(
    new PostTitleWasChanged($this->id, $newTitle)
    );
    }

    protected function applyPostWasCreated(PostWasCreated $event)
    {
    $this->id = $event->id();
    $this->title = $event->title();
    $this->content = $event->content();
    }

    protected function applyPostWasPublished(PostWasPublished $event)
    {
    $this->published = true;
    }

    protected function applyPostWasCategorized(PostWasCategorized $event)
    {
    $this->categories->add($event->categoryId());
    }
    g'vvh,;'
    protected function applyPostContentWasChanged(PostContentWasChanged $event)
    {
    $this->content = $event->content();
    }

    protected function applyPostTitleWasChanged(PostTitleWasChanged $event)
    {
    $this->title = $event->title();
    }
    }

    //Application service
    class PostService
    {
    private $postRepository;

    public function __construct(PostRepository $postRepository)
    {
    $this->postRepository = $postRepository;
    }

    public function createPost($title, $content)
    {
    $post = Post::writeNewFrom($title, $content);
    $this->postRepository->add($post);
    return $post;
    }
    }

    //Read model
    class PostsController
    {
    public function listAction()
    {
    $client = new Elasticsearch\ClientBuilder::create()->build();
    $response = $client->search([
    'index' => 'blog-engine',
    'type' => 'posts',
    'body' => [
    'sort' => [
    'created_at' => ['order' => 'desc']
    ]
    ]
    ]);
    return [
    'posts' => $response
    ];
    }
    }