imJohnBon's avatar

I can't fully wrap my head around Commands.

Let me give you a use case. A user has a profile, something similar to Facebook. When they update their profile, numerous things need to happen:

  1. Conditionally update and resize their profile image (if a new one was uploaded)
  2. Conditionally delete their profile image (if it was asked to be)
  3. "Sync" a HasMany relationship for their favorite movies, which they added in a multiple select box or whatever.
  4. Also sync a HasMany relationship for their favorite TV shows.
  5. Conditionally update/add/resize any number amount of images they may have added to their profile photo gallery.
  6. Update all of the normal info that can just be filled, like their first/last name.

What on earth does the file structure look like for this? Is there just a UserUpdatedProfile command? That doesn't seem right though, we can't just throw all that stuff inside a single command handler, that's no better than throwing it in a controller method.

Is there supposed to be an "UpdateProfileImage" command, an "UpdateFavoriteMovies" command, an "UpdateFavoriteShows" command, etc, that are all called from a base UpdateProfileCommand? After a while it seems there would be a ton of Commands/Handlers.

The use cases I keep seeing online are great and all, "PurchasePodcastCommand", etc. Okay simple enough, if you're just doing that one thing. But once I get into these situations where it seems I need 7 commands for one user action, it feels strange.

0 likes
5 replies
davorminchorov's avatar

There's nothing wrong with having a lot of command / command handler classes.

I think you can do it in 2 ways:

  • One Command + Command Handler and use events for whatever was updated.
  • Multiple Commands and Command Handlers with events if needed.

In the first way, you can use events to listen for when there's an update on the profile info, delete photo, resize photo etc.

The second way seems to be better because you'll probably have different forms for each update feature and not all of them in the same screen. The user will get overwhelmed by information they need to fill if they do.

Oh and it's not one user action, it's multiple user actions but you look at them like it is one.

A good example would be the user settings page on this website. They are split into different screens (or tabs)

jekinney's avatar

Your planing is good. Great foresight. I put each item that needs to be done everything I plan for. Then look for duplication of methods. Combine those. Then prioritize the methods by importance and weather the user needs to wait. Some times a function needs the user to wait but some if it they don't. I split those apart. Check for duplication again.

Then I make commands or events plans by the priorities by weather a function is primary even sometimes (command) and events off secondary.

Save user test data first. As photo in your case might be primary (only upload as data) to save it, then queue an event to resize as that should never be primary (time consuming).

nolros's avatar

@imJohnBon a command pattern is really service class that tends to span multiple types. What I mean by that is often when you create a class you create it for a type, e.g. User, Product, Invoice, etc. Then you aggregate methods a similar nature / type into that class. A command tends to be rather functional rather than type centric e.g. SaveUserProfile could and probably would include multiple classes i.e. User for user data, Image for icon, Settings, Email, Permission, Event, etc. You could place that all in SaveUserProfileService class, but command provides a richer set of services built in. Controllers tend to single class purposed and as such probably wouldn't be a good fit.

Application
    Account
        Models
            EloquentUser
            EloquentCompany
            EloquentProfile
            EloquentProfile
            ...
            Exceptions
                UserException
                ProfileException
            ...
        Repositories
            UserRepository
            CompanyRepository
            ...
            Validation // these can be left in the http directory
            ProfileUpdateRequestValidation 
            ..
        Events
            UserHasRegistered
            ProfielHasBeenUpdate
        Commands
            RegisterUserCommand
            CreateUserProfileCommand
            UpdateUserProfileCommand
        Handler
            ProfileCommandHandler // aggregate into one with multiple methods similar to any class
        Providers // service provider
        Contracts // Interfaces 
        Services // I tend to have a service class for bigger sections
    AccountManager.php // a home / start.php for accounts  
    AccountProvider.php // provider / mutator class if needed

Hope that helps

cm's avatar

@imJohnBon

Think of it this way: Should any of these steps be triggered by another controller or via the command line by itself? Probably yes. A user (or an admin for this user) can only upload a new profile image without doing anything else. They can detele their profile image. They can update TV shows etc.

Whenever you have something that has its own functionality that could be triggered on its own, you wrap this in a command.

Whenever you have something that requires a predefined sequence, you can either make a meta command that calls all other commands. Or you make some sort of service that triggers the commands in the desired sequence.

Your service could be called UserProfileService and it takes all form input and creates the desired commands and fires them off.

pmall's avatar

Im a bit confused too when it comes to large functionality like this.

In 5.1 commands will be renamed jobs, and the explanation is their main focus is queued jobs. It is a nonsense to queue a profile update.

I really think everyone are creating commands now instead of services.

1 like

Please or to participate in this conversation.