Comments (8)
@djmattyg007 @Federkun @kevinsmith --
I suppose this is as good a time as any to reveal Transit, a persistence-to-domain system for Atlas that I've been developing off-and-on for several weeks now:
https://github.com/atlasphp/Atlas.Transit
It is experimental, unfinished, and unsuitable for production. I can guarantee breaking changes, thus the 0.x version. Of note, it lacks Value Object support.
Even though it is not done, it may give you ideas of your own. And of course if you have PRs, send them along.
from atlas.orm.
I was wondering the same thing @djmattyg007. I came out with this:
// PM
class RecordDiscussion
{
public $id;
public $authorName;
public $close;
}
// DM
class Discussion
{
/** @var DiscussionId */
private $id;
/** @var Author */
private $author;
/** @var bool */
private $isClosed = false;
// Make sure that you can create new Discussions only using named constructors
private function __construct() {}
public static function createFrom(DiscussionId $id, Author $author): self
{
$discussion = new self();
$this->id = $id;
$this->author = $author;
return $discussion;
}
public function close(): void
{
if ($this->isClosed) {
throw new Exception('This discussion is already closed..');
}
$this->isClosed = true;
}
public function open(): void
{
if (!$this->isClosed) {
throw new Exception('This discussion is already open..');
}
$this->isClosed = false;
}
// No getters here. I'm moving towards cqrs.
protected static function reconstituteFromDiscussionRecord(RecordDiscussion $record): self
{
$discussion = new self();
$discussion->id = DiscussionId::fromString($record->id);
$discussion->author = Author::fromName($record->authorName);
$discussion->isClosed = (bool) $record->close;
return $discussion;
}
}
The question is: "how can we map the DM and PM?" What do you suggest? Something like this?
class DiscussionTranslator // I can't think of a better name right now
{
public function fromPersistenceModelToDomainModel(RecordDiscussion $record): Discussion
{
$class = new ReflectionClass(Discussion::class);
$method = $class->getMethod('reconstituteFromDiscussionRecord');
$method->setAccessible(true);
return $method->invokeArgs(null, [$record]);
}
public function fromDomainModelToPersistenceModel(Discussion $discussion): RecordDiscussion
{
$record = new RecordDiscussion();
$record->id = $this->getProperty($discussion, 'id')->toString();
$record->authorName = $this->getProperty($discussion, 'author')->toString();
$record->close = $this->getProperty($discussion, 'isClosed');
return $record;
}
// ugly hack
private function getProperty($obj, $prop)
{
$reflection = new ReflectionClass($obj);
$property = $reflection->getProperty($prop);
$property->setAccessible(true);
return $property->getValue($obj);
}
}
If I don't want apply event sourcing, I'm constrained with this?
Finally:
class DiscussionRepository
{
private $mapper;
private $translator;
public function __construct(DiscussionMapper $mapper, DiscussionTranslator $translator)
{
$this->mapper = $mapper;
$this->translator = $translator;
}
public function save(Discussion $discussion)
{
$record = $this->translator->fromDomainModelToPersistenceModel($discussion);
// $this->mapper->update? $this->mapper->insert?
}
public function fetch(DiscussionId $id)
{
$record = $this->mapper->select(['id' => $id->toString()])
->with(['authorName', 'close']);
return $this->translator->fromPersistenceModelToDomainModel($record);
}
}
Full example: https://3v4l.org/oL5OO
from atlas.orm.
how do you go about persisting changes to the domain model back to the storage layer
...
This class doesn't expose all of its properties through getter methods, to avoid it being abused somewhere else in the application.
My general presumption is that getter methods, not being able to change the state of the domain object, is abuse-resistant. The furthest extent I can imagine is that someone might query the state of the object and then use that to decide on a course of action (the opposite of "tell don't ask"). Personally, that's not been a problem I've experienced; being able to "get" the various entities that make up an aggregate, for example, has not seemed at odds with DDD -- but then I don't claim to be a DDD expert so I might have been breaking some rules.
Perhaps providing code examples might help me (and others) understand the problem better ... ?
from atlas.orm.
This is how I have chosen to do it: https://gist.github.com/Federkun/a8e007fc7d9445f100981fb5ccc57407
It's not without of problems, but it's good enough.
from atlas.orm.
I'm running into this same issue myself. Not an Atlas-specific thing per se, just not often seen in many of the other popular ORMs because so many of them couple the persistence layer to the domain layer.
If we've followed the guidance to fully separate persistence from domain (https://github.com/atlasphp/Atlas.Orm/blob/1.x/docs/domain.md#map-from-persistence-to-domain), how do we then take the data in our POPO and get Atlas to update the appropriate row in the DB?
The only solution I've been able to come up with is essentially keeping a cache of previously retrieved Atlas Record instances in an array on a class property of your repository. Then when you inject the POPO (the Thread instance in the example) into your repository's save()
method, the repository matches it up with the cached Atlas Record instance (by primary key), updates the values on the Record accordingly, and passes the Record object into $atlas->update
.
It feels like there's got to be a better way and I just can't see it.
from atlas.orm.
Christmas has come early :)
from atlas.orm.
With Atlas.Transit as at least an example of how to do persist changes back to the storage layer, I am closing this issue. Please comment here if you find reason to re-open it. Thanks all!
from atlas.orm.
The only solution I've been able to come up with is essentially keeping a cache of previously retrieved Atlas Record instances in an array on a class property of your repository. Then when you inject the POPO (the Thread instance in the example) into your repository's
save()
method, the repository matches it up with the cached Atlas Record instance (by primary key), updates the values on the Record accordingly, and passes the Record object into$atlas->update
.
Just coming back to this, and after walking through the code with xdebug, it appears that there was no need for me to do this as Atlas already does this through IdentityMap. Just fetch the record through Atlas as normal and if it was retrieved in the same request, it won't hit the DB again.
Is that right, @pmjones?
from atlas.orm.
Related Issues (20)
- Cached Queries HOT 8
- The name of the static method 'new' in the Atlas class seems to generate a parse error in third party libraries like phpDocumentor HOT 14
- joinWith doesn't work when specifying direction
- On updates, 1 and true and not being treated as the same for bit/boolean columns and values HOT 1
- Cannot delete all records in a many-to-many HOT 4
- Wrong parameters for PDOException? HOT 1
- Updating Many to Many?
- Postgres: problem when using uuid type field HOT 3
- Question: how to use raw insert values in ORM HOT 3
- Support for read-only MySQL generated columns
- Help: how to use advanced ORM feature HOT 5
- Help: Only the first result in a select includes data from related records HOT 7
- [Help Required] Getting Atlas\Mapper\Exception when trying to fetch a record from SQLite HOT 3
- How to use PHP-DI PSR 11 and Repository HOT 1
- Does Atlas.Orm suffer of the problem of useless order by on some ORM prefetches ?
- Row name for Exception::rowNotMapped() and Exception::rowAlreadyMapped() HOT 1
- orderBy missing HOT 1
- Issue with character encoding HOT 12
- Relationships manyToOne NULL HOT 8
- Missing get PDO connection from Atlas ORM HOT 2
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from atlas.orm.