Once I have loaded a domain object from the database I have the key to some of its related objects. For example, when I load an "Organisation", I know the ID of the related "Owner".
I want the Owner property to be lazy loaded, since there's no guarantee I'll be using it during the request or session.
So, the way I see it, the Organisation object could either:
Have an OwnerId property and an Owner property. The Owner property would only be filled on demand (using OwnerId for the lookup). In this case, the only (small) challenge is keeping the two properties synchronised; or
Have an Owner property only. This would initially contain the key (integer) to lookup the Owner. If the Owner is called upon, the value would be replaced by an Owner object. In this case, the (small) challenge would be to avoid type-casting problems.
Which approach is best? Any why? Or are there other approaches? Something else I'm missing?
I'm using PHP, with domain, mapper and service layers. Your thoughts are much appreciated!
I am using Option 1 (see above) and it's panning out fine.
Related
I'm working with Symfony3, and at one point I need to get the class name from an entity object.
I have two tables: role and tier. Both have only two fields: id and name. If I do a query to get these entities, one comes back as a regular entity (as is expected), but the other comes back as a proxy, and I can't understand why.
Tier is a foreign key and belongs to another table, but in this instance I'm only getting the tiers, so I don't see why this should matter.
Can anyone explain how or if there is anything I can do in this scenario?
Its normal that you have proxy. Doctrine use the lazy loading to load entities. I advice you to read this answer:
stackoverflow.com/a/17787070/2377164
Anyway you should be able to use your "proxy" as an entity. Doctrine will load the data you need when you'll try to get some properties
I have a PHP MVC application, and my 'M' has a service layer, mapper layer and domain layer. Where and how should I check to ensure that an object has all it's required properties?
It seems to me that these responsibilities don't belong in the mapper or service layer, so that leaves the domain layer itself. I put a method, checkRequired(), in my base domain class. It checks the object's properties against an array of $_required properties, and throws an error if any are missing.
When retrieving objects from the database, I have been calling checkRequired() as the last command in the object's constructor. If the object is a new entity (i.e. not retrieved from the database), I supply some default values (in the constructor) and then call checkRequired().
While this has been working OK, I now come to put some behavioural methods on my (somewhat anaemic) domain objects, and I run in to trouble. For example, a User can own many Pets, so on my User model I put an addPet() method. I know that I need to pass the Pet object in, since it's best to inject dependencies, and my real method signature is therefore User::addPet(ConcretePet).
But that's the problem! My Pets can't exist without a User (as their Owner), so I can't instantiate ConcretePet! I could make the User optional on the Pet, but this would be a backward step. I could move the contents of checkRequired() somewhere else, but where?
What's the typical way to solve such a common problem?
That checkRequired is not a DDD way. An enntity should be valid all the time. In other words - you should not have a way to put it in an invalid state (like missing properties). How?
When you just have public properties that you set, that's anemic. Properties that you persist in DB should be private. The only way to set them is through methods with a business meaning. These methods should check all the invariants (not just required fields - all kind of constraints that would make an entity valid or not) and prevent the update if some of them are not met.
About User->Pet topic: If the Pet can't exist without the User then probably the User is an Aggregate Root that is responsible for protecting invariants related to User and Pets. That means there should be a method addPet... well... maybe something more meaningful? adoptPet and breedPet (they might have slightly different rules and input)? And this adoptPet should ensure the invariant of the pet having a User... By the way - why User and not an Owner?
But Pet also can be an Aggregate Root. That means it's constructor should require a User parameter.
Note that it depends from the use case what is the aggregate root. In some cases Pet is treated as aggregate root but in case of pet adoption it's a part of User aggregate.
Make a undirectional relationship as possible as you can. If a pet could be tracked alone (I mean without a user), consider it as an aggregate root.
Place a User attribute in Pet but no pets attribute in User. Therefore you don't need to have a addPet() method in User.
If you want to find all pets belonging to a user, use a query instead:
public class PetRepository {
public List<Pet> findByOwner(String uid) {
//omitted codes
}
}
Hope this helps.
When retrieving objects from the database, I have been calling
checkRequired() as the last command in the object's constructor.
Off topic, but this can be problematic. Suppose that the set of required attributes changes at some point such that persisted entities are no longer valid. You still want to be able to reconstitute them, so you shouldn't run that check upon reconstitution. Instead, only run validation upon creation or during behaviors.
With regards to the addPet method, instead of passing an instance of a concrete pet class, pass the data required to create an instance of a pet as method arguments or as an instance of a PetInfo class. This would allow the User class to create a fully valid instance of Pet.
An admin decides to ban some users and gets their IDs. What would be the best way to write it in a flexible and OOP manner?
The suggestions were made without the use of data mappers in mind as I don't see myself using such an approach yet, however if deemed necessary I would highly appreciate some good examples on how to use in such a situation as I have found online examples to be lacking.
Here's what I've thought of this far:
A User object which is made from a database table such as 'Users'. This object should:
a) Have methods to fetch a row and set variables from the data stored?
b) Have the ban state stored in the same database row as username, password and email etc.?
c) Have the ban state map itself to a variable such as public $banned;?
A UserControl object which is made for handling functionality such as banning.
a) Should this object be passed a User object and grab it's ID, or just the ID as a parameter?
b) Should a new UserControl object be created per user it needs to ban or be static?
c) Should this object simply toggle the $banned and have the User object save itself afterwards, or do the logic itself; set the 'banned' column in the Users table on the row where the given ID is?
I figured that if I put all these methods into the User object it would soon become a God object with $user->hasImages();, $user->isBanned(); and $user->sendNewsFeed();, so I could need some advice on how to do this in a manner that would be flexible enough to add and remove functionality easily in an environment where a large number of users is handled and the use of collections and such is used.
Id recommend an ACL implementation. Its more than youre asking about currently but i have a hard time believing you wont need to manage access at varying levels (admin, guest, user, etc.) to varying things (forums, images, pages, etc.). By using an ACL you could use the same code for everything and a "ban" would simply be an ACL which denies access to everything.
You can take a look at the Zend_Acl component for reference but whether you need something that robust or not is your decision.
If you have a UserStatus field in the User object and represent Banned, Guest, User, Mod, Admin, whatever in that object then just see if their status is Banned.
I'm looking for best practices to fetch users created content.
I have $user object form 'security.context' and I need to get single record created by this user by some $record_id,
so what I should do?
$this->getDoctrine()->getRepository('AcmeRecordBundle:Record')
->findOneBy(array( 'id' => $record_id, 'user' => $user->getId() ));
This doesn't look good to me, because I have lot's of information that needs to be fetch looking for user too(to don't let other users try get it by some id). And for any content( personal photo, some other private content) I have to pass 'user' => $user->getId() ?
Or it's better to create UserRepository with all these functions? getRecordById($id), getPhotoById($id), getPrivateInformationById($id), etc.
I was working with Rails a little, and there I was able to define current_user method
def current_user
return #current_user if defined?(#current_user)
# ....
end
and then just use it as
current_account.records.find(params[:id])
is there any possibility to make it work like this with Doctrine2 and Symfony2? Like
$user->getRecords()->find($recordId)
In any situation you have to specify user which you pass to your function, which deal with the fetching logic inside custom repository as specified in official documentation for Doctrine.
Of course you have to pass the user's id for the "WHERE" sql clause, just because ROR did it magically behind the scenes (which is a very bad practice imo), doesn't mean it didn't do it at all.
As for the other matter, both solutions are ok:
Fetch data from the particular repository, and pass the object id + the user's id, or:
Create methods which internally get user's id and put them in queries
And remember that user's id is fetched only once during the request, so don't worry about getting it from the security context too much.
You need to implement Symfony 2 ACL features. This allows you to specify ownership for "domain objects" (individual instances of DB classes) and what kind of access users have on a domain object. Then you can use for example the JMSSecurityExtraBundle and implement access controls based on object ownership. Once implemented your users won't be able to modify each other's objects (by parameter manipulation) and you won't need the additional parameter in your queries.
Here are a few relevant links:
Access Control Lists (ACLs)
JMSSecurityExtraBundle
Personally I found the repository classes to bloat things a bit in a small to mid-size application. Not sure what your approach is, but most everything I've read (and what I went w/ in a recent Doctrine 2 app) was to have a 'service' layer which manipulated the entities. This is b/c in D2, implementing save / delete etc in the entities undermines the purpose of the system which is to alleviate knowledge of persistence from the entities and treat them as Plain Old Php Objects (TM) ;)
The thing that looks odd to me about your query is passing an primary key id and a User id to fetch a User. Seems to me like the pk of the User table would be the user id, or at the very least if the user id isn't the pk (not sure why that would be) you should be able to get the records w/ just the pk. Here's the method to fetch a User object in my system
/**
* #param int $iId user id
*
* #return object
*/
public function fetch($iId)
{
return $this->_oEm->find('AwesomeApp\Entity\User', $iId);
}
The current user sort of function you're looking for should be related to the session in your application. In zf I've created a session handler that persists the doctrine User object to session storage, then when the session is read I re-attach the User object to the Entity Manager. You probly want to do something similar in sf, then a 'getCurrentUser' call would return the same User object as pulling it from the database. Storing a User object in the session prevents the need to go back to the database for it on every page load, for example if you just stored the User id in the session.
At the end of the day you're 'supposed' to put complex select queries into repositories, but this is obviously left to User discretion when it comes to best practices. In this case, when you have just a pk, I'd say there's no point to writing a repository class.
Bit of an abstract problem here. I'm experimenting with the Domain Model pattern, and barring my other tussles with dependencies - I need some advice on generating Identity for use in an Identity Map.
In most examples for the Data Mapper pattern I've seen (including the one outlined in this book: http://apress.com/book/view/9781590599099) - the user appears to manually set the identity for a given Domain Object using a setter:
$UserMapper = new UserMapper;
//returns a fully formed user object from record sets
$User = $UserMapper->find(1);
//returns an empty object with appropriate properties for completion
$UserBlank = $UserMapper->get();
$UserBlank->setId();
$UserBlank->setOtherProperties();
Now, I don't know if I'm reading the examples wrong - but in the first $User object, the $id property is retrieved from the data store (I'm assuming $id represents a row id). In the latter case, however, how can you set the $id for an object if it has not yet acquired one from the data store?
The problem is generating a valid "identity" for the object so that it can be maintained via an Identity Map - so generating an arbitrary integer doesn't solve it.
My current thinking is to nominate different fields for identity (i.e. email) and demanding their presence in generating blank Domain Objects. Alternatively, demanding all objects be fully formed, and using all properties as their identity...hardly efficient.
(Or alternatively, dump the Domain Model concept and return to DBAL/DAO/Transaction Scripts...which is seeming increasingly elegant compared to the ORM implementations I've seen...)
You would use the setId function if you are controlling the IDs, if you want to override the data store ID, or if you want to update/delete the data without having to retrieve it first (i.e. already have the ID from a POST).
Another alternative would be calling setId() to reserve an ID by "querying" (insert a record) the data store for the next available ID.
It's not really relevant what the ID is set to until you actually need to use it to reference something. Calling setId with no parameter would do nothing except flag the object as new data. Once you actually try to "get" the ID is when one would be generated. Sort lazy ID generation.