Laravel Controller: Move Logic to Action or Service Class

Поделиться
HTML-код
  • Опубликовано: 2 авг 2021
  • In this live-coding experiment, I will try to move the logic outside of the Controller, and create an Action class, and later a Service class, performing the same thing. Which one do you prefer?
    Video of Creating That API Controller: • Laravel API Controller...
    Pull Request to API Challenge: github.com/LaravelDaily/Larav...
    - - - - -
    Support the channel by checking out our products:
    - Enroll in my Laravel courses: laraveldaily.teachable.com
    - Try our Laravel QuickAdminPanel: bit.ly/quickadminpanel
    - Purchase my Livewire Kit: livewirekit.com
    - View Laravel Code Examples: laravelexamples.com
    - Subscribe to my weekly newsletter: bit.ly/laravel-newsletter
  • ХоббиХобби

Комментарии • 116

  • @dalok100
    @dalok100 Месяц назад

    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!

  • @JimOHalloran
    @JimOHalloran 2 года назад +67

    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  2 года назад +15

      You're right, well explained

    • @demonaudio2563
      @demonaudio2563 2 года назад

      Exactly.

    • @aleksandarkrasic8324
      @aleksandarkrasic8324 2 года назад

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

    • @DanAbrey
      @DanAbrey 2 года назад +3

      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 2 года назад +6

      @@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.

  • @andrewwwlife
    @andrewwwlife 2 года назад +12

    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

  • @michalbabic8636
    @michalbabic8636 2 года назад +1

    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.

  • @mmohamedbadr
    @mmohamedbadr 2 года назад

    Thank you, it's great video

  • @daleryanaldover6545
    @daleryanaldover6545 2 года назад +1

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

  • @NSlides
    @NSlides 2 года назад

    Cool stuff.. we are using services approach..

  • @nirajgautam403
    @nirajgautam403 2 года назад

    Already working with these techniques

  • @sateesh.ilavenil
    @sateesh.ilavenil 2 года назад +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  2 года назад +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.

  • @NehalPatelTheBest
    @NehalPatelTheBest 2 года назад +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?

  • @hederperez7336
    @hederperez7336 5 месяцев назад

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

  • @izzymane9591
    @izzymane9591 2 года назад

    keep doing this gods work

  • @amrullahdev8895
    @amrullahdev8895 2 года назад +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?

  • @jacquesmatike9289
    @jacquesmatike9289 2 года назад +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

  • @69leostereo
    @69leostereo Год назад

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

  • @feryadialoi2244
    @feryadialoi2244 2 года назад +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 2 года назад +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 2 года назад +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

  • @gamerneversleep4200
    @gamerneversleep4200 2 года назад

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

  • @invgreat5608
    @invgreat5608 Год назад

    THANK YOU!!!!! 🥰

  • @mdranacse19
    @mdranacse19 2 года назад

    Thanks ❣️

  • @Code2Master
    @Code2Master 2 года назад

    thanks a lot❤

  • @soopercoco91
    @soopercoco91 2 года назад +1

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

  • @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 ?

  • @ayoubjamouhi6890
    @ayoubjamouhi6890 2 года назад

    I do dependency injection of service in controller

  • @mohamadcheaib
    @mohamadcheaib 2 года назад +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  2 года назад +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.

  • @antonlindell6102
    @antonlindell6102 2 года назад +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  2 года назад +1

      No, haven't used it

    • @antonlindell6102
      @antonlindell6102 2 года назад

      @@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  2 года назад

      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.

  • @squattingnomad6298
    @squattingnomad6298 2 года назад

    Services don't require registration and binding to app?

  • @AfmpJR
    @AfmpJR 7 месяцев назад

    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  7 месяцев назад

      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.

  • @VadimBesedin
    @VadimBesedin 2 года назад +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  2 года назад

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

    • @VadimBesedin
      @VadimBesedin 2 года назад

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

  • @godstimejohn2673
    @godstimejohn2673 2 года назад

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

    • @LaravelDaily
      @LaravelDaily  2 года назад +1

      Isn't it the same what I just did?

    • @godstimejohn2673
      @godstimejohn2673 2 года назад

      @@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 2 года назад

      @@godstimejohn2673 it's already explained in the video bro

    • @godstimejohn2673
      @godstimejohn2673 2 года назад

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

  • @rakeshthapa9541
    @rakeshthapa9541 2 года назад +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  2 года назад +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 2 года назад

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

  • @JuanMarchant
    @JuanMarchant 2 года назад

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

    • @LaravelDaily
      @LaravelDaily  2 года назад +1

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

  • @Sinres2
    @Sinres2 2 года назад

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

    • @LaravelDaily
      @LaravelDaily  2 года назад +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

  • @ugayashan8659
    @ugayashan8659 2 года назад

    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

    • @bm-software
      @bm-software 4 месяца назад

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

  • @user-gt2eh8ne2x
    @user-gt2eh8ne2x 2 года назад +8

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

    • @LaravelDaily
      @LaravelDaily  2 года назад +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.

    • @user-gt2eh8ne2x
      @user-gt2eh8ne2x 2 года назад +2

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

    • @mohamedahmedradwan9367
      @mohamedahmedradwan9367 2 года назад +1

      @@LaravelDaily please do

    • @rizkypujiraharja
      @rizkypujiraharja 2 года назад

      can't wait for this :)
      thank you

    • @akunbeben
      @akunbeben 2 года назад +1

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

  • @Aalii6
    @Aalii6 7 месяцев назад

    👍👍

  • @muhammadhateem3090
    @muhammadhateem3090 2 года назад

    @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  2 года назад

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

    • @muhammadhateem3090
      @muhammadhateem3090 2 года назад

      @@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  2 года назад

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

  • @JhErEl9
    @JhErEl9 2 года назад

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

    • @LaravelDaily
      @LaravelDaily  2 года назад

      What do you mean by transactions?

    • @JhErEl9
      @JhErEl9 2 года назад

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

    • @LaravelDaily
      @LaravelDaily  2 года назад

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

  • @ShotoCon
    @ShotoCon 2 года назад

    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  2 года назад +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.

  • @glmarco24
    @glmarco24 2 года назад

    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  2 года назад

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

    • @glmarco24
      @glmarco24 2 года назад

      @@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  2 года назад +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 2 года назад

      @@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

  • @helluci6449
    @helluci6449 Год назад +1

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

  • @kerolesmonsef4179
    @kerolesmonsef4179 2 года назад

    what is the different between action and repository pattern

    • @LaravelDaily
      @LaravelDaily  2 года назад +1

      Watch some videos here mentioning repository patterns, and you will feel the difference: ruclips.net/channel/UCTuplgOBi6tJIlesIboymGAsearch?query=repository

  • @bekkarghezal6173
    @bekkarghezal6173 2 года назад

    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  2 года назад +2

      Helpers: ruclips.net/video/nsHS1e5QOYw/видео.html
      And: laravelexamples.com/tag/helpers
      HTML rendering: can't answer that in a RUclips comment, too broad question.

    • @bekkarghezal6173
      @bekkarghezal6173 2 года назад

      @@LaravelDaily Thanks a lot

  • @abdulbasitsalah2918
    @abdulbasitsalah2918 2 года назад

    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  2 года назад +1

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

    • @abdulbasitsalah2918
      @abdulbasitsalah2918 2 года назад

      @@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

  • @eas7112
    @eas7112 2 года назад

    what is the different between action and trait ?

    • @LaravelDaily
      @LaravelDaily  2 года назад

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

  • @javieru5871
    @javieru5871 2 года назад

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

    • @LaravelDaily
      @LaravelDaily  2 года назад +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 2 года назад

      @@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.

  • @JaimeNetoBr
    @JaimeNetoBr 2 года назад

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

    • @LaravelDaily
      @LaravelDaily  2 года назад +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.

  • @Diego-eb9we
    @Diego-eb9we Год назад

    What about Traits? where does it fit?

    • @LaravelDaily
      @LaravelDaily  Год назад +1

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

    • @Diego-eb9we
      @Diego-eb9we Год назад

      @@LaravelDaily thank you so much!

  • @dixonwilliam6694
    @dixonwilliam6694 21 день назад

    where to validate the request in service?

    • @LaravelDaily
      @LaravelDaily  21 день назад

      Validation should be in form request, probably

  • @user-ki9or2lt9r
    @user-ki9or2lt9r 2 года назад +4

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

  • @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.

  • @fahimanzam7015
    @fahimanzam7015 2 года назад

    Do a multiple image upload crud video please!

    • @LaravelDaily
      @LaravelDaily  2 года назад

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

  • @luizmeier
    @luizmeier 2 года назад +1

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

  • @TomHartill
    @TomHartill 2 года назад +1

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

  • @IvanMarkovicJapy
    @IvanMarkovicJapy 2 года назад +1

    else branch should be removed in controller. Not need it

  • @haroldpepete
    @haroldpepete 2 года назад +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

  • @javieru5871
    @javieru5871 2 года назад

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