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.
Related
I am currently building a website with the following user types:
customers
caregivers
partners
agent/mediator
system user (<- special case, I'll talk to you in a moment)
Each user type should only be allowed to do certain things.
However, the system users are somewhat different.
These should be able to be divided into groups, and these groups should also have different rights.
My customer should be able to create/edit these groups including the assignment of given rights. However, it should not be possible to edit the other user types.
I have already seen this ACL packages (https://github.com/spatie/laravel-permission and https://github.com/JosephSilber/bouncer).
But I don't think they support that.
I have also thought of the following approach: There is no user type "system user", but the users are assigned the type of group, and in the code, I check if this type is "customer","caregiver","partner" and "agent". If this is not the case, the user is automatically a system user.
Is there perhaps an open source project that has such a similar approach? I'm currently having a hard time with all the controller classes at the moment (have now merged them into a single user controller and have the $type in the route and a factory class return the right model to me, and then call up a factory again to return the respective service class <- feels totally wrong and badly implemented).
Currently, Joseph Silber is building multi-tenancy for Bouncer. I think that will fit your needs, but it's not released yet for the time I'm writing this.
Also, it's practically 100% sure that you will need to extend a package like that or fork it to adapt to your needs. Looks like a very specific code that will need modifications.
I know this is a duplicate question but i think it will help others because there are a lot of similar apps that have these kind of table relationships:
So the question is what would be the optimal solution for all relationships in this schema using the Eloquent?
How many Models and Controllers to make?
First of all, you need to understand that not all tables in a database represent an entity.
For example, tables like users, posts, comments are entities. Whereas posts_users, comments_posts are not: they are here for technical reason, to materialize the relation between 2 entities.
Only entities need a model: it makes no sense to have a model for a relation table.
Even if a table holds information like date_created, it does not make it an entity. This is just a data related to the relation. For example, the table users_roles may have a column named date_assigned, to know when a given user was assigned a given role. It's not entitity for all that.
Second, you need to understand what a controller is for. The role of a controller is to handle a request and provide a result. Result can be a view, an error (HTTP 404), or just the fact that an action has been successfully done.
You must also make the difference between the class called Controller (or any child that extends this base class) and an actual controller. The actual controller is the code that will handle the request. A Controller class can have more than one method to handle requests.
It's all a question of organization: generally, Controller classes are used to group methods within the same scope: user login, logout, subscription, password reminder are all the same scope. All these controllers could be in different classes or functions. It does not matter. Each method is a controller. They are grouped in the same class because they have the same needs (check user is logged in, to know if login is required, if subscription page can be displayed, etc.) and they are in the same scope, which just make sense when you think of it. That's just logical: you know where to search when you need to change something about user identification (even if you are new on the project).
So you need a model for these entities:
User
Offer
Invoice
Category
The controllers you'll need depends on what you want/need to do with this data. There's no ready-to-use answer to this part of your question.
Use a Controller class for:
user authentication (if you need some)
user management (backoffice)
invoice management (edit, mark paid, list of late payments, etc.)
categories management (create, edit, delete)
offers management
But depending on your application, you may need more. Only you can really say. There's no bad answer to this question: if you think some controllers should be separated for better organization, do it. If you think you should group 2 or more, do it. There's no rule. You have to keep your code clear and well organized. It must suit your needs. That's all.
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.
The context is a educational administration system built on the Zend Framework. We are implementing a RESTful MVC to handle pretty much all data interactions with clients. Relationships between resources are mapped in the database with foreign keys etc.
Example case: a teacher creating a report on a specific student.
We currently have a role-based permissions system that can be tailored to the level of the individual role (using, eg, teacher_5 as the role name). Therefore we can easily restrict access to an already existing report (by generating permissions in the report model that allows edit/put permissions on the report only to the tutor role who created it, say). The problem comes on creation. In order to add a report a user can post to /reports, say, the following data:
{ achievement: "4", performance: "5", student_id: "10" }
The problem is that tutors are only allowed to create new reports on a certain subset of student_ids - those students that they are teaching.
One approach would be to treat this as a validation issue on that field. The issue with this is that we want to protect ourselves from making mistakes, and that is not easy to do with validation (the code would have to know in advance that special validation is expected on certain fields).
The other would be to somehow extend our permissions system to a completely granular one (i.e., there would be a permission for every field in every model), and then extend our current permissions system to responding to paramaterised permissions checks. So if we wanted to know if the current user has permissions to add student_id 10 to a report on creation, we would end up with something like
if ($acl->isAllowed($resource, $role, $action, $field, $value))
where $resource would be a report model, $role would be the teacher teacher_5, $action would be "post", $field would be student_id, and $value would be 10. The acl class would essentially handle a call to the $resource itself.
We are not sure which direction to take, but presumably this is a fairly common issue, so we are wondering what approach other people have taken.
What about having another table containing the student_id's that each teacher tutors. Then you can easily check if the teacher is allowed to do the insertion. Another benefit from that solution would be the ability to extract statistics about the whole class, like average grades, attendance etc
I have at least one model in my Yii project that will need to reference a particular user ID. In my SQL for the model I have something like CONSTRAINT FOREIGN KEY (user_id) REFERENCES User(id). I was going to go ahead and create a User model when I came across the docs for CUserIdentity. I have to admit I am confused. Is a CUserIdentity a user or a state associated with a particular user-case? I would like to use as much of the built-in Yii features as possible since they handle a lot of security-related issues from what I understand, and I am aware of the existence of some modules like srbac that handle user authentication and registration management. Please guide me in the right direction. (Also at issue: what is the relationship between models and components?)
First off, do go ahead and create a User model, you will need it.
With that out of the way: CUserIdentity represents the concept of "who the user is", while the User model represents "information about a user of my application". CUserIdentity is applicable in all cases where there is more than one kind of user (i.e. guest), while the User model is only applicable when you are storing information about the users yourself. Admittedly, in most cases both will be applicable and this is what creates the confusion.
Usually, the relation between the two is that CUserIdentity, in order to answer questions such as "who the user is", "is the user allowed to access this resource" etc. queries the User model from the database to get the information it needs to answer these questions. This relationship between the two concepts is also documented in the definitive guide to Yii. After e.g. authenticating the user, it would expose some or all of the information on the User model through its own properties (which you would have to define).
To give an example of a scenario where there would be no User model, think about a website that lets you log in using your LDAP user account. When the CUserIdentity::authenticate method is called, the component would authenticate the credentials against the LDAP server and after a successful authentication would again grab any other relevant information and expose it through its own properties.