Laravel Controller: Move Logic to Action or Service Class

Поділитися
Вставка
  • Опубліковано 27 жов 2024

КОМЕНТАРІ • 117

  • @JimOHalloran
    @JimOHalloran 3 роки тому +69

    I’m not keen on the abort calls in the action/service class. I think one of the main responsibilities of the controller is to decide which response should be returned (although the content of that response might come from a template or API resource, so having some responses in the service or action, and others in the controller doesn’t seem right to me. I could easily imagine coming to a project like this somewhere down the line and trying to figure out why it’s returning a 500 result all of a sudden. In this case I’d hope to be able to see the abort call in the controller itself rather than having to dig through the action service classes to find it, especially if they’re complex. Throwing an exception out of the service would be my preferred option for this reason.

    • @LaravelDaily
      @LaravelDaily  3 роки тому +17

      You're right, well explained

    • @aleksandarkrasic8324
      @aleksandarkrasic8324 3 роки тому

      Exactly, services should return null if there is an error, and controllers should abort if variable content from service class is null.

    • @DanAbrey
      @DanAbrey 3 роки тому +4

      Totally right. Decoupling to an Action is pointless if you're passing in a request to the action. Your Action is coupled to the request, it's no longer independently callable or testable.

    • @DanAbrey
      @DanAbrey 3 роки тому +7

      @@aleksandarkrasic8324 return null if there's an error? Why?
      That's what exceptions are for if it's something that the application should be handling (ie if it's something you're checking "if null then do this")
      Null means empty, nothing. Not error.

    • @JimOHalloran
      @JimOHalloran 3 роки тому +1

      @@DanAbrey Null (or false) seemed to be a common thing a long time ago. In the event of an error an API function would return a sentinel value like null or false and then you'd call something like "get_last_error()" to find out what went wrong. You can see this in the cURL PHP extension for example. Where a function may not work and that's expected I like to return a special value, and reserve errors for truly exceptional cases. Imagine I get a customer id from a user, and I want to call Customer::find($id). I have no ides whether the $id exists, and it's entirely possible that it doesn't. In this case I'd rather ::find() return a null than throw an exception. (Of course Eloquent also has ::findOrFail() if you'd rather the exception)

  • @andrewwwlife
    @andrewwwlife 3 роки тому +13

    As for me one of the main criteriums of a good application is the ability to call core logic from console, that's why I'm a huge fan of services that I can call from every place in my application

  • @dalok100
    @dalok100 5 місяців тому

    This reminded me of the correct way to use controllers, a concept I learned years ago with the Spring Framework. While others suggested using services in the comments, the simplicity of actions made it easier for me to understand and cleared the way for further learning. Thx!

  • @michalbabic8636
    @michalbabic8636 3 роки тому +2

    1/ Checking, if someone can or can't do something is responsibility of Request (or Gate if necessery). You use authorization method in request always as true. But you can move this logic here. In single responsibility principle, store method is not about checking user.
    2/ For this reason I preffer service layer which each part of logic is separated. Request checks user authorization and validate inputs. If is needed, throws exception which is handled by Exception Handler.
    Next Controller call service layer which call all neccessery service methods. If is no exception throws, model is returned to controller and controller make response - ideally through Resource layer.
    3/ This approach is nice for later adding new features without updating existing code and for writing unit tests (one for request, other for services) and one global as integration test with calling endpoint and testing valid response structure.

  • @mohamadcheaib
    @mohamadcheaib 3 роки тому +3

    In my opinion, in the action class the handle should return voice, but in your code in some condition it returns voice in other condition it returns void.
    Then in the controller you recheck again the voice if it was recently created, which is a repetition, so the handle function should return voice and the conditions should be in the controller based on the returned voice object.
    I dont know maybe i'm wrong but i prefer the insert update logic of controller to be in the controller and seperate the logic only in one case if i'm sure that the logic will be reused in other classes or methods

    • @LaravelDaily
      @LaravelDaily  3 роки тому +4

      Fair points about inconsistency, agree it could be improved.
      But I disagree that it should be in Controller if it's 10+ lines of code, it should be some separate class, just maybe structured better than I did.

  • @feryadialoi2244
    @feryadialoi2244 3 роки тому +6

    The action is more popular called by Command Pattern, when every method in service make the service class too big to maintain then every method moved to one class to maintain individually

    • @maurovalvano5707
      @maurovalvano5707 3 роки тому +1

      But a lot of time, a service method can call another service method and it's more easy and fast to fix them both. I hate to jump from a file to another and back

    • @feryadialoi2244
      @feryadialoi2244 3 роки тому +1

      @@maurovalvano5707 that's right, every way have their own pro cons, in action/command doesn't mean you can't have another method except the main/action one, you still can have the provate method, or even call another service/command, from constructor or another way

  • @jacquesmatike9289
    @jacquesmatike9289 3 роки тому +5

    Services are more interesting because as it has many methods, the service is not directly related to the main controller. Then another controller could have a need of one method of that service.
    For example having a paymentService that has a create_wallet(), that method could be called from any other class like a listener to create user wallet when any new user registration.
    Be in an handle method couldn't be that easy

  • @sateesh.ilavenil
    @sateesh.ilavenil 3 роки тому +7

    Thank you so much for the video. Instead of a try/catch in each controller method, can we not have a global Handler.php(as given by Laravel) which handles anything that is not caught by controller & service/action?

    • @LaravelDaily
      @LaravelDaily  3 роки тому +6

      Yes, that's also a good practice, but depends on the scenario, how many of the exceptions are "standard" to be caught by a Handler, or how many of them are individual, so should be caught in Controller.

  • @daleryanaldover6545
    @daleryanaldover6545 3 роки тому +1

    I've seen the service implementation on my previous rails job, didn't know I could do it with laravel too.

  • @antonlindell6102
    @antonlindell6102 3 роки тому +2

    Love your videos, thank you for a great resource. Are you planning on making a video of Laravel Octane, with pros and cons?

    • @LaravelDaily
      @LaravelDaily  3 роки тому +1

      No, haven't used it

    • @antonlindell6102
      @antonlindell6102 3 роки тому

      @@LaravelDaily I see. I would love to see you trying it and hearing your thoughts, to me it seems incredible but have yet to try it as well.

    • @LaravelDaily
      @LaravelDaily  3 роки тому

      From what I've read about it, it would be useful for 0.001% of Laravel projects. So for now, not planning to shoot a video on that topic.

  • @ДанилКравцив
    @ДанилКравцив 3 роки тому +8

    Hey, I have a question. How Laravel passes VoiceAction or VoiceService in your controller method as input parameter?

    • @LaravelDaily
      @LaravelDaily  3 роки тому +12

      It's a long thing to answer, I may shoot a separate video about Laravel Container and its logic, can't answer in a comment.

    • @ДанилКравцив
      @ДанилКравцив 3 роки тому +2

      @@LaravelDaily okey, thank you, will watch it :)

    • @mohamedahmedradwan9367
      @mohamedahmedradwan9367 3 роки тому +1

      @@LaravelDaily please do

    • @rizkypujiraharja
      @rizkypujiraharja 3 роки тому

      can't wait for this :)
      thank you

    • @akunbeben
      @akunbeben 3 роки тому +1

      in a nutshell, it's similarly like Dependency Injection cmiiw

  • @AfmpJR
    @AfmpJR 11 місяців тому

    06:11 I saw you recommending in another video (Jr code review) to not leave the abort for the service, since it's not supposed to do that, but throwing an exception to the controller, which is the right place to do such thing.

    • @LaravelDaily
      @LaravelDaily  11 місяців тому

      Services should inform controllers that something went wrong.
      Controllers need to CONTROL, meaning decide what to return to the user if that something went wrong.

  • @hederperez7336
    @hederperez7336 8 місяців тому

    Iam applying this knowledge to my proyect rigth now, and i like how looks the code

  • @rakeshthapa9541
    @rakeshthapa9541 3 роки тому +2

    I believe the main purpose of single responsibility classes is to promote code re-usability.
    Lets say I need to do the same action for api/web/command then the best thing would be to take all the logic into one place and use it everywhere and send the response as per where it is used. If I am using the action in api controller then handling the status code and returning data as json structure is the controller responsibility similarly if used in web it is the controller responsibility to either send some html or redirect to another page.
    What I don't like in this video is that you are passing Request class as an argument to the action class which will limit the reuse of the action class as the request structure will be different for api/web/command so we should rather work with something like DTO (a plain class which contains almost no logic and contains only information needed to do the action). In this way your action class will be independent of how the request is made and hence can be easily tested without doing any http calls.
    Most of the time you don't need to do this but if you want to make you controller shorter then just use service classes(or model or private/protected method in the controller) to hide your code from controller to somewhere else and don't separate the logic into many classes because as the project grows you will have hundreds of classes and it would be much harder to debug.
    Moving logic into multiple place is always pain in the ass So if you want to do it, then do it properly, write tests for your classes so that you can find out if there is any problem more easily(but still you will struggle) .
    And lastly for me, most of the time I use laravel for building api only and all the logic goes into controller or some service/helper class and yeah no tests(in general).

    • @LaravelDaily
      @LaravelDaily  3 роки тому +1

      Thanks for the valuable comment, a few valid points. I wouldn't use DTO, but probably would change Request class to a few exact variables which would be used in Action. But then it's more like a Service.

    • @rakeshthapa9541
      @rakeshthapa9541 3 роки тому

      @@LaravelDaily sure but then I would also remove the request clsss typehint in the action.

  • @ling6701
    @ling6701 2 роки тому

    Thanks. So if I understand correctly, the action class is just any class with no particular laravel magic. It's just a convention that would have worked in any framework with dependency injection ?

  • @SXsoft99
    @SXsoft99 2 місяці тому

    Why not add the check for created directly from the SQL query with an additional where condition and check for null model variable? It should be faster from an memory standpoint

  • @soopercoco91
    @soopercoco91 3 роки тому +1

    I usually create actions as invokable classes just for keeping things clean.

  • @NehalPatelTheBest
    @NehalPatelTheBest 3 роки тому +1

    Great content sir, this way we can handle request from frontend and API from the same Action/Service class logic. Can we implement this Service/Action class with livewire components?

  • @squattingnomad6298
    @squattingnomad6298 2 роки тому

    Services don't require registration and binding to app?

  • @helluci6449
    @helluci6449 Рік тому +1

    Does that count as a "bad practice" if I create multiple Actions, then just call those in Services?

  • @amrullahdev8895
    @amrullahdev8895 3 роки тому +2

    thanks for all the tutorials that you've made, I've been watching your video about optimization lately but is there any way to StressTest LaravelApp, I currently using artillery for that, but I don't quite understand, would u like to make a video about stress test?

  • @69leostereo
    @69leostereo 2 роки тому

    nice video , could you please explain, why ... controllers should be short ?

  • @nirajgautam403
    @nirajgautam403 3 роки тому

    Already working with these techniques

  • @VadimBesedin
    @VadimBesedin 3 роки тому +1

    Is there an instruction or an article that explains the difference and best practice usage cases for all the types of Laravel classes?
    Actions, Helpers, Jobs, Services, etc...

    • @LaravelDaily
      @LaravelDaily  3 роки тому

      I haven't seen anything like this. Maybe it's a signal that I should do it myself :)

    • @VadimBesedin
      @VadimBesedin 3 роки тому

      @@LaravelDaily With your explanation skills - That would be great!

  • @invgreat5608
    @invgreat5608 2 роки тому

    THANK YOU!!!!! 🥰

  • @jniyaz
    @jniyaz 3 роки тому

    Cool stuff.. we are using services approach..

  • @mmohamedbadr
    @mmohamedbadr 3 роки тому

    Thank you, it's great video

  • @gamerneversleep4200
    @gamerneversleep4200 3 роки тому

    I am new to laravel. What is good practice for backend + blade components?

  • @abdulbasitsalah2918
    @abdulbasitsalah2918 3 роки тому

    hello Povilas
    i filtering my orders using get method (not POST),
    when the text field is empty, the request value for that field will be empty string, in that case, it will be true in the $request->has and the where condtion that apply to the model, inside the if will be executed and it return [] array
    Order::with('user')
    if ($request->has('brand')) {
    //return 'has brand';
    $query->where('brand', trim($request->brand)
    }
    i that any way the $reqeust->has() not pass empty string ?

    • @LaravelDaily
      @LaravelDaily  3 роки тому +1

      You need this: laraveldaily.com/less-know-way-conditional-queries/

    • @abdulbasitsalah2918
      @abdulbasitsalah2918 3 роки тому

      @@LaravelDaily thanks thats a great tip
      and alos i find anther solution "insteat of $request->has using $requtest->filled()" that way it only that condtion will be true if the value for input exist

  • @mdranacse19
    @mdranacse19 2 роки тому

    Thanks ❣️

  • @izzymane9591
    @izzymane9591 3 роки тому

    keep doing this gods work

  • @JuanMarchant
    @JuanMarchant 3 роки тому

    Hi. This same example but on livewire component... Where inyected this new action class o service class on livewire component.
    Thnaks

    • @LaravelDaily
      @LaravelDaily  3 роки тому +1

      It would be the same, just change Controller to Livewire component, and inject classes that you need.

  • @john.godstime
    @john.godstime 3 роки тому

    Thank you, I love your videos. Can you please do a video on how to use both actions and service?

    • @LaravelDaily
      @LaravelDaily  3 роки тому +1

      Isn't it the same what I just did?

    • @john.godstime
      @john.godstime 3 роки тому

      @@LaravelDaily ok the question should have been, what scenario can we combine the two patterns (service and action). Maybe we have a service that also uses action.

    • @jacquesmatike9289
      @jacquesmatike9289 3 роки тому

      @@john.godstime it's already explained in the video bro

    • @john.godstime
      @john.godstime 3 роки тому

      @@jacquesmatike9289 ok. I will have to rewatch it (maybe I watched it in a hurry at first). Thanks bro.

  • @ugayashan8659
    @ugayashan8659 3 роки тому

    Hey L.daily I'm working on a laravel API. in the User service method I have a function called refreshJwt and I'm trying to get Auth::id which is returned in loginUser function in the same service class, inside the refreshJwt function to generate JwtToken, but it is null. is there any workaround?? I tried getting user id from the session as well, they didn't work

    • @wodashekaf
      @wodashekaf 7 місяців тому

      Not sure if I understand you correctly, but It seems you need user details from Auth Facade. Try below
      Auth::user()->id;

  • @javieru5871
    @javieru5871 3 роки тому

    In this context, an Action and a Service are both referring to the same concept application?

    • @LaravelDaily
      @LaravelDaily  3 роки тому +1

      Not really, Action is usually for one single action, like a Job, and Service are usually for many methods grouped for some purpose.

    • @javieru5871
      @javieru5871 3 роки тому

      @@LaravelDaily Ok I see, so for example, a Service might be appropriate for a set of CRUD methods or many public methods designed for certain business purposes around a Model Entity, while an Action is just one single public entry point maybe with many private properties inside to achieve some certain functionality not necessarily related to a Model.

  • @Sinres2
    @Sinres2 3 роки тому

    What do you think about use __invoke magic method to call action class?

    • @LaravelDaily
      @LaravelDaily  3 роки тому +1

      I don't see a big difference between __invoke() and handle().
      To me personally, __invoke() is associated in my mind with invokable CONTROLLERS and not other classes: laravel.com/docs/8.x/controllers#single-action-controllers

  • @tarekadam9652
    @tarekadam9652 2 роки тому +1

    Action seems fine. The naming is arbitrary but logical and easy to follow. Service should probably be reserved for actual services that register and boot etc. On a side note, if you have a bunch of controller work that isn't part of the return - then you can should use jobs. (not useful here because we return $voice) If you don't have job queue infra - just use the "sync" que and your jobs will handle inline upon dispatch.

  • @glmarco24
    @glmarco24 3 роки тому

    I always check earlier things like $question->user_id == auth()->id(). I would create middleware isQuestionOwner and abort there. It aborts earlier, it may be reused in another controller and looks cleaner and more separated to me. How do you feel about that?

    • @LaravelDaily
      @LaravelDaily  3 роки тому

      But can it be used in an Artisan command? In a unit test?

    • @glmarco24
      @glmarco24 3 роки тому

      @@LaravelDaily you can write separated tests for service and for middleware also, though I am not feeling sick when I don't have 100% coverage. Not sure about artisan command, maybe it's possible to trigger middleware in constructor method

    • @LaravelDaily
      @LaravelDaily  3 роки тому +1

      Yes, you're right, it is POSSIBLE. But not convenient, in my opinion. Again, it's all a personal preference, so use whatever works for YOUR case.

    • @glmarco24
      @glmarco24 3 роки тому

      @@LaravelDaily that's true. However, you might end up with "never use middleware", because "unit tests and artisan command" can always apply to any middleware

  • @muhammadhateem3090
    @muhammadhateem3090 3 роки тому

    @laravel Daily, i want to perform some business logic on the $request which is coming through view, so should i use a service class for that business logic as i should not put it into controller? can u answer or suggest any video who is doing the same.

    • @LaravelDaily
      @LaravelDaily  3 роки тому

      What exactly do you mean by business logic? Can you provide code example? (May be unfinished code)

    • @muhammadhateem3090
      @muhammadhateem3090 3 роки тому

      @@LaravelDaily like i want to transfer amount from one account to another account, and i am getting the amount from my view, while the accounts are stored in db.from business logic I meant any logic that is more than simply one line of code.

    • @LaravelDaily
      @LaravelDaily  3 роки тому

      Ok, I see. Then I guess any external class would do, Service is the most typical example.

  • @JaimeNetoBr
    @JaimeNetoBr 3 роки тому

    Couldn’t part of this verifications be done inside a Policy?

    • @LaravelDaily
      @LaravelDaily  3 роки тому +1

      Yes it could, but then it would throw 403 code instead of 500. I've mentioned it in a previous video of that mini-series.

  • @Code2Master
    @Code2Master 3 роки тому

    thanks a lot❤

  • @offilawNoone
    @offilawNoone 18 днів тому

    Sometimes it seems to me that programmers, having nothing better to do, invent something new for themselves. With such logic, we can go even further and eventually we will have a million classes with three lines of code in each.

  • @JhErEl9
    @JhErEl9 3 роки тому

    thanks, I've a question, the transactions should go in the service or in the controller?

    • @LaravelDaily
      @LaravelDaily  3 роки тому

      What do you mean by transactions?

    • @JhErEl9
      @JhErEl9 3 роки тому

      @@LaravelDaily laravel Eloquent manual transaction, with try/catch

    • @LaravelDaily
      @LaravelDaily  3 роки тому

      Oh, I see. Not sure, they could go in either class, it's your choice.

  • @bekkarghezal6173
    @bekkarghezal6173 3 роки тому

    Thank you for these very useful little free lessons,
    Can you please, tell me how to create laravel str helper, as diffHuman or plural ..., also, I would like to create a PHP script for HTML rendering,

    • @LaravelDaily
      @LaravelDaily  3 роки тому +2

      Helpers: ua-cam.com/video/nsHS1e5QOYw/v-deo.html
      And: laravelexamples.com/tag/helpers
      HTML rendering: can't answer that in a UA-cam comment, too broad question.

    • @bekkarghezal6173
      @bekkarghezal6173 3 роки тому

      @@LaravelDaily Thanks a lot

  • @ayoubjamouhi6890
    @ayoubjamouhi6890 3 роки тому

    I do dependency injection of service in controller

  • @Aalii6
    @Aalii6 11 місяців тому

    👍👍

  • @Diego-eb9we
    @Diego-eb9we 2 роки тому

    What about Traits? where does it fit?

    • @LaravelDaily
      @LaravelDaily  2 роки тому +1

      Here are the resources about Traits, read/watch those examples: laraveldaily.com/tag/traits

    • @Diego-eb9we
      @Diego-eb9we 2 роки тому

      @@LaravelDaily thank you so much!

  • @dixonwilliam6694
    @dixonwilliam6694 4 місяці тому

    where to validate the request in service?

    • @LaravelDaily
      @LaravelDaily  4 місяці тому

      Validation should be in form request, probably

  • @luizmeier
    @luizmeier 3 роки тому +1

    A philosophical differente:
    Actions : one time class with one method, quick;
    Services: when there is more methods (i.e., store, update etc);

  • @kerolesmonsef4179
    @kerolesmonsef4179 3 роки тому

    what is the different between action and repository pattern

    • @LaravelDaily
      @LaravelDaily  3 роки тому +1

      Watch some videos here mentioning repository patterns, and you will feel the difference: ua-cam.com/channels/TuplgOBi6tJIlesIboymGA.htmlsearch?query=repository

  • @user-ki9or2lt9r
    @user-ki9or2lt9r 3 роки тому +4

    nice video, but I feel bad when I see 'else' like the one in the controller instead of early return

  • @fahimanzam7015
    @fahimanzam7015 3 роки тому

    Do a multiple image upload crud video please!

    • @LaravelDaily
      @LaravelDaily  3 роки тому

      Added this topic to the future videos, currently I have 100+ topics in that idea list so can't promise anything.

  • @ShotoCon
    @ShotoCon 3 роки тому

    To abstract data from the controller for a 3rd part API integration, would you use a Service Provider (as in the final example), or create a package, or a combination of the two? If you have a video or article, I can review, it would be greatly appreciated.

    • @LaravelDaily
      @LaravelDaily  3 роки тому +3

      It depends on the exact integration and how it should work. I don't really like theoretical question, I like practical examples with the exact situation/problem and then I can work on the answer.

  • @haroldpepete
    @haroldpepete 3 роки тому +1

    that refactor could be even better, service method is too long and it does a lot of thing, clean-code and solid talk about single responsability, make this code like that not allow reuse it

  • @TomHartill
    @TomHartill 3 роки тому +1

    It gets to a point where your code is more instantiating different classes and calling methods than actual logic 🤣

  • @IvanMarkovicJapy
    @IvanMarkovicJapy 3 роки тому +1

    else branch should be removed in controller. Not need it

  • @javieru5871
    @javieru5871 3 роки тому

    Controllers should be Thin & Athletic, on the contrary, Services should be Fat & Happy....

  • @eas7112
    @eas7112 3 роки тому

    what is the different between action and trait ?

    • @LaravelDaily
      @LaravelDaily  3 роки тому

      See Trait examples: laravelexamples.com/tag/traits
      See Action example: laravelexamples.com/tag/actions