2

I'd like to ask other opinions about code structuring of business logic on Laravel applications, mainly regarding permissions at the row level.

For those that don't know it, Laravel is a MVC framework for PHP, much like Rails.

For the sake of understanding, let's suppose a multi-tenant application where each user has his own albums and pictures, so far so good.

  • Now, each user can invite others to collaborate (by uploading photos) into his album.
  • Both, the album's owner and collaborator that uploaded the picture may be able to delete or update information about that picture.
  • Only the owner may edit the album and invite new collaborators.
  • Collaborators can remove themselves of the album if they want so.

Pinterest should be a nice example of something similar, but our application is probably 3 or 4 times more complex. The question is: where should I handle that kind of logic?

Laravel proposes the approach of having repositories, entities and services, which I don't fully understand, probably because of the lack of good examples. So the obvious first choice to meet those deadlines was to put it all on controllers (ew!). Now, digging into refactoring, there are many possible ways to un'spaghettize our code:

  • I've seen people implement ACL at row level (looks kinda dumb and overkill)
  • It would be possible to turn models into behavior aware objects and not only data containers, something like $album->add_photo($photo) and check permissions at that function
  • It would also be possible to override model's save method and do there those checks
  • Or, follow the Laravel proposed road of having separate layers of concern

I suppose that having methods like $album->can_be_edited_by($user) may simplify the displaying of 404 erros on routes not allowed, hiding view's links as well as validating before saving the models

Which would you recommend, and does anyone know any simple, but understandable, example of repositories, entities and services not using .NET? Thanks!

Edit: I guess that a full ACL system would cause excessive overhead, since there may be thousands of resources associated with each user, but only one role per kind of association. For instance, pictures will have an uploader_id and albums will have an owner_id.

tereško
  • 58,060
  • 25
  • 98
  • 150
vFragosop
  • 5,705
  • 1
  • 29
  • 31
  • you might find this somewhat related: http://stackoverflow.com/q/3430181/727208 – tereško Feb 22 '13 at 08:52
  • Your's is indeed a pretty nice answer. Although, something we wish to avoid for now is having ACL per row, specially since there are no groups and at the worst case there are 2 distinct permission types per resource, being one already bounded by an external `owner_id` key. We suppose that having a full ACL system would cause excessive overhead. Your explanation about the layers made somethings clearer for me, tho. – vFragosop Feb 22 '13 at 21:04

2 Answers2

1

I could be wrong but I think ACLs are OBJECT based permissions (i.e., a user can or can't delete photos in GENERAL). What you want is more custom MODEL based permissions (row level like you said), i.e., a user can delete photos that they themselves created (SPECIFIC ones).

Most Laravel packages are designed for object based permissions I think, but not https://github.com/deefour/authorizer - this one is a great hidden gem. We don't use it in our project but I found that it really covers all the bases we'd need.

We have really advanced model permissions on our app, I have them scattered throughout my models, but I take a very model centric approach, which isn't necessarily very "laravel-esque". In your example with delete, I would override the delete method in your model or listen for the eloquent event and prevent it there. If you have to prevent read/write on certain attributes you could even do that by extending your validator or using custom mutators/getters, serializers or listening on events. More on where to add business logic in my question/answer here: https://stackoverflow.com/a/27804817/796437

I'm still trying to find the best approach, if I do I'll update this - but thought I'd post.

Community
  • 1
  • 1
Sabrina Leggett
  • 9,079
  • 7
  • 47
  • 50
0

In Laravel you can use Policies or use solutions, like Symfony Voters. For Laravel exists same package - Laravel Simple Voters.

Using this, you can check access to custom objects, looks like this:

Access::isGranted('edit', $post) // current user can edit this post?

You can put this logic, to example, into middleware, if you wish check requests to controllers.

maximkou
  • 5,252
  • 1
  • 20
  • 41