azeós's avatar
Level 3

Separating complete views logic from partial UI calls

I'm refactoring an application with Laravel 11 and Inertia 2 (Vue.js). One problem I'm currently facing is that I have the logic from the views and some "JSON responses" inside the same controller (behind the same policy).

Let me give you a simplified example:

Tables:

users:

  • id
  • name

roles:

  • id
  • name (admin / teacher / student)

role_user:

  • id
  • role_id
  • user_id

divisions:

  • id
  • name (1st A, 1st B, 2nd A, etc)

subjects:

  • id
  • name (math, literature, etc)

division_user:

  • id
  • division_id
  • user_id

division_subject:

  • id
  • division_id
  • subject_id

attendances:

  • id
  • division_id
  • subject_id
  • user_id
  • date
  • present (bool)

Permissions:

  • users.viewAny
  • users.view
  • users.create
  • users.update
  • users.delete
  • users.restore
  • users.forceDelete
  • divisions.viewAny
  • ...
  • attendances.viewAny
  • ...

Controllers:

UserController:

  • index
  • show
  • create
  • store
  • edit
  • update
  • destroy

DivisionController:

  • index
  • ...

  • An "admin" can create users, divisions and subjects.
  • Each division has its own subjects.
  • A "teacher" can take attendance.

The logic for creating users, divisions and subjects it's pretty straight forward, a simple resource controller with matching permissions and Inertia responses for each method.

Now, what happens with the "attendances" logic? Lets say that the "teachers" are the ones that can take attendance, but they can not create users, divisions and subjects.

When they access to AttendanceController@index they see 2 selects:

  • Division
  • Subject

When a division is selected I need to get the subjects that correspond to that division. And that's where the problems begin.

I need to make a call to a route that will only return a list of subjects associated with a division.

Today that logic is within SubjectController@index, but that generates 2 main problems:

  • The index() method now has to return an Inertia response if its an Inertia call and do something different if its not and return a JSON object (the subjects list for the select).
  • That method is behind a SubjectPolicy that checks if the user has the subjects.viewAny permission. But I don't want to give a teacher that permissions, because they must not have access to the subjects index page.

So, for me one thing is being able to access the subject index to make some CRUD actions and another thing is being able to "get a list" of subjects just for some forms/UI need.
I think that having something like "API" controllers and permissions might be the right approach, but I'm not building an API, so what should I call it? How can I separate those things?

get: /subjects
App\Policies\Views\SubjectPolicy@viewAny > subjects.viewAny
App\Http\Controllers\Views\SubjectController@index

get: /json/subjects
App\Policies\Json\SubjectPolicy@viewAny > json.subjects.viewAny
App\Http\Controllers\Json\SubjectController@index

Something like that? Now what I need to "remember" is that when I give a teacher the attendances.viewAny permission, I must give them the json.subjects.viewAny permission too or otherwise they will not be able to use the division/subject select.

The "real" logic probably will be in a SubjectService that will be called from those two controllers.

Again, this is a simplified example, this happens with a lot of models.

What do you think about that approach? Something different to recommend? Thanks!

PS: I read this thread but that's not exactly my problem.

0 likes
0 replies

Please or to participate in this conversation.