Kevin
Kevin

Reputation: 554

Laravel 5 - Clean code, where to keep business logic (controller example)

Below example of 'store' method of my controller Admin/MoviesController. It already seems quite big, and 'update' method will be even bigger.

The algoritm is:

  1. Validate request data in CreateMovieRequest and create new movie with all fillable fields.
  2. Upload poster
  3. Fill and save all important, but not required fields (Meta title, Meta Description..)
  4. Then 4 blocks of code with parsing and attaching to movie of Genres, Actors, Directors, Countries.
  5. Request of IMDB's rating using third-party API

My questions:

Upvotes: 5

Views: 9137

Answers (1)

manix
manix

Reputation: 14747

You need to think on how you could re-utilize the code if you need to use it in another classes or project modules. For starting, you could do something like this:

Movie model, can improved in order to:

  • Manage the way on how the attributes are setted
  • Create nice functions in functions include/manage the data of relationships

Take a look how the Movie implements the functions:

class Movie{

    public function __construct(){

        //If 'Meta Title' is empty, then fill it with the name of the movie
        $this->seo_title = empty($movie->seo_title)
            ? $movie->title 
            : $otherValue;

        //If 'Meta Description' is empty, 
        //then fill it with the description of the movie
        $movie->seo_description = empty($movie->seo_description)
            ? $movie->description 
            : $anotherValue;

        $this->updateKinopoisk();
    }

    /* 
    * Parsing comma separated string of countries and attaching them to movie 
    */
    public function attachCountries($countries){

        foreach($countries as $item) {
            $name = mb_strtolower(trim($item), 'UTF-8');

            $country = Country::where('name', $name)->first();

            if ( empty($country) ) {
                $country = new Country();
                $country->fill(['name' => $name])->save();
            }

            $movie->countries()->attach($country->id);
        }
    }

    /*
     * Update Kinopoisk information
     */
     public function updateKinopoisk(){}

    /*
     * Directors
     */
     public function attachDirectors($directors){ ... }

     /*
      * Actores
      */
      public function attachActors($actors){ ... }

      /*
       * Genders
       */
       public function attachActors($actors){ ... }
}

Poster, you may considere using a service provider (I will show this example because I do not know your Poster model looks like):

public class PosterManager{

    public static function upload($file, $movie){
        $poster = \Image::make($file);
        $poster->fit(250, 360, function ($constraint) {
            $constraint->upsize();
        });

         $path = config('app.images') . $movie->id.'/';

         if(! \File::exists($path)) {
            \File::makeDirectory($path);
        }

        $filename = time() . '.' . $file->getClientOriginalExtension();
        $poster->save($path . $filename);

        return $poster;
    }
}

Config file Try using config files to store relevant application constanst/data, for example, to store movie images path:

'images' => storage_path() . '/images/movies/';

Now, you are able to call $path = config('app.images'); globally. If you need to change the path only setting the config file is necessary.

Controllers as injected class. Finally, the controller is used as a class where you only need to inject code:

public function store(CreateMovieRequest $request) {
    $movie = Movies::create($request->except('poster'));

    /* Uploading poster */
    if ($request->hasFile('poster')) {
        $file = $request->file('poster');
        $poster = \PosterManager::upload($file, $movie);
        $movie->poster = $poster->filename;
    }

    if (!empty($request->input('genres'))) {
        $genres = explode(',', $request->input('genres'));

        $movie->attachGenders($genders);
    }

    // movie->attachDirectors();
    // movie->attachCountries();

    // Apply all changes
    $movie->save();

    return redirect('/admin/movies');
}

Upvotes: 11

Related Questions