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.
Related
I'm writing a timesheet application which would be used by employees and approved/rejected by supervisors. A timesheet has various permissions and only people with certain roles can do certain actions (like for example only a supervisor can approve a timesheet and only if it belongs to an employee under the supervisor's list of employees).
I'm trying to figure out how to structure my list of business objects (models). There are various validations I need to do before I can invoke methods like GetTimesheet or SaveTimesheet or ApproveTimesheet. See the following psuedo-code for an understanding of how my app should work:
GetTimesheetByUserIdAndMonth:
-Validate parameters like UserId, Month-Year value
-Check Permissions:
- If Logged In User is A Supervisor, then see if Timesheet belongs to either this user or to a user under Supervisor's list of Employees
- Else, check if Timesheet belongs to logged in User
SaveTimesheet
-Validate parameters like UserId, Month-Year value
-Check Permissions (same as above)
-Check if user has write ability for timesheet (for example if user had already submitted timesheet before then he can't re-save or re-submit)
SubmitTimesheet
-See if user has a supervisor assigned
ApproveTimesheet, RejectTimesheet
-Logged in User must be a Supervisor, otherwise throw an error
I'm thinking I would need a MyAccount class for the person who is logged in, a User class to represent the person who the timesheet belongs to, a Timesheet class, and maybe some sort of Validation class.
Can someone tell me how best to architect this code and what sort of classes and validation methods I should have? I already have this code working in 100% procedural code...it is very difficult to read and maintain. I'm not looking for full implementation details, just an overall class achitecture/structure. Please give me some ideas and provide me some psuedo-code how to accomplish the above tasks. I can provide more details if necessary.
Thanks in advance.
In your question I can understand 3 different kinds of problems to solve.
The hierarchical structure
Permissions
Validations
A possible pattern to solve this problem is Composite pattern. Some general guidelines to follow can be listed as below.
Use an abstraction which can be used to refer all kinds of users (supervisors, peers etc). Something like 'User'.
Use composite to maintain hierachy.
The abstraction 'User' should have methods like getWritePermission: boolean to provide permissions.
Validations should be decoupled from the core structure. You should maintain those logic using a separate worker class, which will be called at the very higher level of the api call.
I take it you are using an mvc approach. If so you are already on the right track.
Each User action needs a controller. What you already wrote down suits this scheme.
The tricky part is how you store the user:supervisor relation? And is it 1:n or m:n? Anyway I'd go with a User and a Timesheet model (backed by a database) and then go as needed. You don't need to differentiate between user myself and other users on a class object level.
Inside you are your own judge. A Timesheet validator class and a class for checking user rights seem to be needed (additionally to the login system).
Think the following
UploadTimesheetController -> TimesheetValidatorClass -> TimesheetModel -> Database
ViewTimesheetController -> CheckUserHasAccess -> TimesheetModel -> TimesheetView
It's a bit simplistic and not formally correct but I hope you get the idea.
The question here is about how to handle correctly DDD DE, lets say we have this very simple example (i know that for simple projects DDD is not needed, but this is just an example). We have User (Aggregate root) and UserProfile (Value Object), so tables are:
user
- id
- email
- password
user_profile
- country_id
- first_name
- second_name
As we know our code should express behavior and should not be data-centric, so for example on one of our hexagonal side (UI browser) we have this application service to handle situation:
//UserService application service
public static function update($formDTO)
$user->changeCountry($form->country);
$user->changePassword($form->password);
$user->attributes = $form->userData();
$user->save(); // here we use AR not DDD ORM like; you can see this as entityManager->flush(); if you like Hibernate or Doctrine.
And method changeCountry looks like:
public function changeCountry($country)
{
if ($this->country->id != $country->id) {
$oldCountry = $this->country;
$this->moveToCountry($country);
...->eventsManager->raise(new UserMovedToCountryEvent(
[
'user' => $this,
'oldCountry' => $oldCountry,
'newCountry' => $newCountry,
],
))
}
}
Questions about changePassword and changeCountry methods:
Should we call save in $user->changeCountry() ? Should such behavior methods (changePassword and changeCountry) persist object to storage after changing it?
If it should then should we wrap it in transaction? I think yes, since we have here DomainEvent.
What if there will be no DomainEvent, should we still persist object to storage? In this case this method (changeCountry or moveToCountry) used to express behavior but should it start transaction ? Is there any recomendations for this one?
Or maybe we only should rais one domain event UserProfileChanged with params like $oldInfo $newInfo, but as for me this one lacks the domain.
The point is to make things correct, but without unneeded amount of persistance calls. I know that i should not think about persistance on domain layer, but getting 20 sql updates instead of 1 is not a good solution.
Domain objects should not be concerned with persistence. Repositories take care of aggregate persistence. You would get your aggregate from the repository, invoke methods on the aggregate and persist it again in the application layer. This leads to two database calls; one SELECT and one UPDATE - rolled up in one transaction.
var user = repository.GetById(userId);
user.MoveToCountry(country);
repository.Update(user);
I know this is just an example, but make sure you capture the user's intent. That update-method looks like your building a CRUD application, but are trying to reverse-engineer intent after the fact - which might make sense when you're refactoring etc..
I am quite new to DDD and have some fundamental problems that i cant really understand.
Consider we have a User entity. A User has some Friend's (one to Many).
There are 2 possible solutions to fetch the friends.
Solution 1:
user.getFriends()
The Problem here is that all the friends have to be loaded or I am forced to use a Proxy.
If i use a Proxy it feels for me like cheating because the entity must not have an instance of the Repository. Can the Proxy have one?
Solution 2:
Avoid the getFriends Method and load the Friends Based on the User Repository, like:
userRepository.getFriendsOf(user)
This could sometimes be a good idea, but where to stop here? Whats about an AddressRepository for accessing user Addresses, or ?
I think you should look at it from perspective of Aggregate Roots.
In case of user.getFriends() - the user seem to be AR with associated friends which I don't think is correct. The definition of AR says "that we treat as a unit for the purpose of data changes". Friends are outside of the Boundary of user AR.
Considering the above the other option seem better - userRepository.getFriendsOf(user)
I'm not sure that either of them are correct. I think from a DDD point of view, the code is supposed to use the Ubiquitous Language of the domain. In that regard, getters are frowned upon.
Why are you getting the friends of a user? The public methods of User should reflect the ubiquitous language.
For example if your domain is a social networking site, users should have methods to update status which will internally notify friends etc. How the User knows who its friends are or how they are queried is hidden as an implementation detail.
One thing to keep in mind is that you shouldn't use your domain model for querying. So you do not want to be lazy-loading or applying any other fetching strategies.
You also need to identity your aggregates. An aggregate is loaded in its entirety from the data store.
In your case if a Friend class can only ever exist in the context of a User then it is part and parcel of the User and its life-cycle is linked to that of the User. That means that when the User is deleted (conceptually, as one probably would not want a hard delete) then the associated Friend instances are deleted also.
So if a Friend represent the association between users then it probably only contains the User Id. So you could go with a list of Ids in that case. This would depend on your domain.
I would guess that you very rarely would need to load the entire list of User instances that are friends of another user. If you need related data you could implement a light-weight query layer.
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.
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.