Skip to content

Instantly share code, notes, and snippets.

@raykolbe
Created May 21, 2013 20:36
Show Gist options
  • Star 6 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save raykolbe/5623035 to your computer and use it in GitHub Desktop.
Save raykolbe/5623035 to your computer and use it in GitHub Desktop.
CQRS is simple!
<?php
namespace CQRSSample\Domain\Model
{
/**
* Please read this. It may be interesting to you. You can ridicule me ONLY if you read the whole thing.
*
* CQRS is NOT about different data sources and is NOT about Event Sourcing.
* CQRS IS about breaking out your reads and writes. It's powerful and simple!
*
* That being said, you can use CQRS virtually everywhere. Think about when you use a repository (DDD Repository). A
* DDD repository is used to deal with your domain models. A lot of people tack on pagination for handling large data
* sets, custom find methods for application-specific reasons, etc. A DDD repository SHOULD only be used for domain-
* specific reasons. Do you REALLY have a business need for pagination, searchability on ANY attribute of a domain-
* object, etc? Your APPLICATION and UI specify these needs but your business rules probably do not.
*
* Maybe I'm crazy.
*/
class Person /* Note: We assume Name is the identifier for Person. It is unique. Just like mom says I am. */
{
private $name = null;
private $contactInformation = null;
public function __construct(Name $name, ContactInformation $contactInfo)
{
$this->name = $name;
$this->contactInformation = $contactInfo;
}
}
class PersonRepository /* Assume concrete implementation w/persistence store attached to it (duh). */
{
public function personWithName(Name $name)
{
// @todo Search for a person and return the hydrated aggregate.
// In the real-world this would probably be personWithId($id) or findById($id) (not expressive; total crap!).
}
public function store(Person $person)
{
// @todo Add to unit of work. Remember, transactions happen in application layer (Application Services, Controller, etc.)
}
}
/* Value Objects */
class Name
{
// @todo Implement
}
class ContactInformation
{
public function __construct(EmailAddress $email, PhoneNumber $phone)
{
// @todo Implement
}
}
class EmailAddress
{
// @todo Implement
}
class PhoneNumber
{
// @todo Implement
}
}
namespace CQRSSample\Application;
use Doctrine\DBAL\Connection;
{
class PersonSearchApplicationService
{
private $connection = null;
public function __construct(Connection $connection)
{
$this->connection = $connection;
}
public function allPeopleWithNameStartingWith($namePart, PagingOptions $paginationOptions)
{
// @todo Implement. We use Connection here to work with lower-level SQL...or whatever persistence store.
// We return a paginated list. An alternative would be to return a lazy-loaded collection that we can
// pass to some pagination service or framework (e.g. Zend Paginator/Doctrine Paginator, etc.).
// Note that you can:
// 1) Return the aggregates used from the repository (meh) or
// 2) Return a new read-model (booya!). This is a better option because now we remove any weird eager/lazy fetching
// rules, AND we can be very specific about what data to return, AND it's a read-only model, so you don't have to
// do any DTO transformations in your controller. Also makes for searializing objects for storage or transfer
// much nicer (also PHPers, stop adding toArray() on your aggregates, it's not appropriate.).
}
public function allPeople()
{
// @todo Implement. Assuming it returns a lazy-loaded collection of some sort.
}
}
}
/**
* Okay, that's all. Harass me on Twitter - twitter.com/raykolbe
*
* I really would like the PHP community to talk more about DDD/CQRS. For those who have not been practicing it, don't
* be scared. Hit me up and we can talk (IRC, IRL (beer++), email, carrier pigeon (not Pidgin)).
*
* Oh ya, check out http://cqrs.files.wordpress.com/2010/11/cqrs_documents.pdf for more CQRS stuff. Also the Googler (obv.)
*/
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment