This looks pretty slick.
Analogue ORM - An 'Eloquent-like' Data Mapper
Hello, I wanted to share with you a 'weekend' project I've been working on for the few past months, and that I just released on Github.
It started as an experimental fork of Eloquent, an attempt to decouple the Model from the database. and evolved into a fully featured Data Mapper ORM built on top of Illuminat/Database.
It's in a fully functionnal Beta stage, and works with both L4 / L5. I'd like to hear your thoughts guys on it !
Github page : https://github.com/analogueorm/analogue
Yes looks like a great package ! Thanks
Very cool! I've been recently looking at better leveraging DDD, but Eloquent tends to fight me the whole way, which has lead to some frustration on my part.
Can I use a custom mapper class to use complex value objects vs. a simple constructor with scalar values? For example, my table columns might look like this:
- id
- first_name
- middle_name
- last_name
- prefix
- suffix
- sworn_date
And I want to use a mapper to create entities using this constructor:
class JudicialOath
{
public function __construct(Name $name, SwornDate $date)
{
$this->name = $name;
$this->swornDate = $date;
}
}
class Name
{
public function __construct($first, $last, $middle = '', $prefix = '', $suffix = '')
{
/* snipped for brevity */
}
}
@thepsion5 : Not yet, but it's the one feature I want to implement next. I have thought a lot about it last week actualy. now I have to test several different approach to come up with the most elegant solution.
I've experimented with my own data mapper implementation and that was a big stumbling block for me - I had a hard time figuring out how to manage that kind of complex transformation without just manually mapping everything. I'm very interested to see what you come up with.
@thepsion5 : Had some time to implement it and it worked out quite well :)
Here's the Mappings :
namespace Acme\Maps;
use Analogue\ORM\EntityMap;
class UserMapping extends EntityMap{
public $timestamps = true;
public $softDeletes = true;
protected $embeddables = ['name' => 'Acme\Users\Name'];
....
}
use Analogue\ORM\ValueMap;
class NameMapping extends ValueMap
{
protected $attributes = ['first_name', 'last_name'];
}
The Value Objects & Entity
namespace Acme\Users;
use Analogue\ORM\ValueObject;
class Name extends ValueObject {
public function __construct($first_name, $last_name)
{
$this->first_name = $first_name;
$this->last_name = $last_name;
}
}
...
use Analogue\ORM\Entity;
use Hash;
class User extends Entity {
public function __construct($email, $password, Name $name)
{
$this->email = $email;
$this->password = Hash::make($password);
$this->name = $name;
}
}
Now it make possible this kind of usage :
$userName = new Name('john', 'smith');
$user = new User('bob@example.org', '1234', $userName);
$userRepository->store($user);
The only restriction for now is that the name of attributes used in a ValueObject must be the one used in the database table.
Great package. Thanks !
This looks really nice! What are your future plans, is there a roadmap or something similar somewhere?
Two things which came to my mind, which I wasn't able to figure out. Does Analogue ORM support "Accessors & Mutators" like Eloquent? And secondly, how are Value Objects stored in the database? Serialized? In a separate table? Thanks for your feedback! :)
I've been playing around with this for a while now - What would really help me out is some more complicated mapping examples -- perhaps some more complex entity classes and an example structure that includes all of the relationship types.
Also, I notice that you use a collection object in the readme to store the *Many relationships - but the simple illuminate collection class has no add function - using an eloquent collection gives us the add function but it seems disingenuous to be using a collection intended for Eloquent instances and storing in it bare Entity classes.
Anyways, I will keep poking at it in the meantime. Some more documentation would definitely help anyone wanting to use the package out for sure.
@abbajbryant, there's an EntityCollection - maybe that one works.
The package is intresting will work around with it and see wat it has to offer
@abbajbryant : as @thasmo , EntityCollection classes are the way to go.
@Thasmo : Value Objects are stored in the table associated to the Entity which uses them. They are not serialized (1 value object attribute = 1 database column).
I updated the package for L5 compatibility a few weeks ago. I definitely need to add a more complete documentation, hopefully I'll get some time a the next days/weeks. If you have questions/issues don't hesitate to post them on github, it really helps me figure out which part of the package may be confusing/ needs more doc. Cheers!
Hi RemiC, This looks interesting. On a side note, I have private GIT repos for a SQL lib I wrote before Laravel and a Mongo based file system for JS and using a Laravel controller. Any advice on making it public and setting up the composer file? Having trouble organizing info on this. Would like to use composer to load these PHP libs into my Laravel projects.
Regards, Jim
you are the instance to my singleton, the object to my orientated :)
omg I laughed so much :D
@nolros : haha, that's real abstract poetry ! @abbajbryant
Just made a big upgrade on the package, now with full documentation & unit tests, and L5 integration.
I toyed with it a lot on the current application I'm developping, which help a lot making it more streamlined and easier to use. And I admit I'm having quite a good time putting back logic into my models, after having spent the whole last year abstracting them away...
I think it's really worth checking out for Laravel users interested in DDD.
@thasmo : cheers for pointing out the issue with repository, helped me find a really nice way to make them DI friendly.
Great @RemiC I will try that and comment my results here. Great work!!
Thanks again.
You're welcome @codeatbusiness .
Let me know if some areas are unclear/need more documentation.
Cheers!
@RemiC I really like this project, I swear I'll give it a try soon.
In fact I fear I like it so much that I'd want to redo all my projects with it lol
@RemiC, nice job. New features and the docs are slick!
@pmall: not much to be afraid of, if you already followed some kind of repository pattern. moving your Eloquent models into Analogue entities are almost a matter of cutting & pasting your classes into Entity & EntityMap. Client code is likely to be slimmer too. You can safely create your domain in a new subfolder, run tests, then switch interface's implementation once it all turn greens.
@RemiC the only thing I dislike is the mappers being automagically associated with the entities because of a naming convention (Entity => EntityMap). I like analogue because I code everything and there is no magic. Reading the doc I was like "how the hell does the entity know which mapping to use ? It is defined nowhere".
I would suggest to be more explicit for the definition of this convention. Maybe in the service provider so I can spot directly there is this convention and I can override it in this place.
This is a minor detail, everything else is cool :) Love the pattern with the repository containing the mapper etc... !
@pmall : You can set which EntityMap to use, by invoking Analogue::register($entity, $entityMap), before the first time you call Analogue::mapper for the given entity in the request
.Analogue will only try to autodetect if no map are explecitely registered. This 'automagic detection' is just aims form a better workflow and more clarity. I actually found myself several time wondering what was wrong with my relationship and I just forgot to register the maps.. so..
Anyway, I will make it more explicit in the documentation. Cheers for the feedback!
@RemiC i'm finally using your package for a side project (kind of small blog) and I must say your package is great. Everything fall in place pretty well. I love the repository with included mapper approach it feels very natural. Used it with auth and socialite and it works perfectly.
Only one thing about the analogue-auth package I felt it strange when you say in the doc you have to specify the use of Analogue\LaravelAuth\User in the auth conf. What I want is to use my own user object so I made a bare class App\User and made it extend the analogue user class.
Anyway please keep maintaining this package and everyone interested in a data mapper approach should take a look at this :) Thanks :)
@pmall : Of course you can use your own User implementation. The doc for LaravelAuth is mainly intended to be plug and play, I didn't go so much into details. I'm planning to write a specific L5 integration tutorial which will cover all these in details.
About the package itself, I began refactoring some internal parts to make it easier to maintain & contribute, along with abstracting out the mapping process to be able to add other storage drivers in the future. So yes, I have plans for it :)
Thanks for feedback !
@RemiC It would be cool if analogue entities could implement model url generation.
@pmall : I have to think about this, as entities right now are not self aware of their primary key, that would require quite a shift in the design.
On the otherhand, it's quite easy to roll your own custom entity and extends from it :
use Analogue\ORM\Entity;
use Illuminate\Contracts\Routing\UrlRoutable;
class CustomEntity extends Entity implements UrlRoutable {
protected $primaryKey = 'id';
public function getRouteKey()
{
return $this->attributes[$this->getRouteKeyName()];
}
public function getRouteKeyName()
{
return $this->primaryKey;
}
}
@RemiC oh yes of course entity don't know about their primary key. I still don't totally made the mental shift ahah :)
Thanks for the example.
Please or to participate in this conversation.