Laravel 5 - 清洁代码,保存业务逻辑(控制器示例)

Kev*_*vin 5 php model-view-controller coding-style laravel laravel-5

下面是我的控制器Admin/MoviesController的'store'方法示例.它看起来已经很大了,"更新"方法会更大.

算法是:

  1. 在CreateMovieRequest中验证请求数据并使用所有可填写字段创建新影片.
  2. 上传海报
  3. 填写并保存所有重要但非必填字段(元标题,元描述..)
  4. 然后是4段代码,解析并附加到流派,演员,导演,国家的电影.
  5. 使用第三方API请求IMDB评级

我的问题:

  • 我应该将所有这些代码移动到Model并将其划分为更小的方法,例如:removeGenres($ id),addGenres(Request $ request),...
  • 有一些最佳做法吗?我说的不是MVC,而是Laravel的功能.目前为了保持一些逻辑,我只使用Request for validation.

    public function store(CreateMovieRequest $request) {
    
    $movie = Movies::create($request->except('poster'));
    
    /* Uploading poster */
    if ($request->hasFile('poster')) {
        $poster = \Image::make($request->file('poster'));
    
        $poster->fit(250, 360, function ($constraint) {
            $constraint->upsize();
        });
    
        $path = storage_path() . '/images/movies/'.$movie->id.'/';
    
        if(! \File::exists($path)) {
            \File::makeDirectory($path);
        }
    
        $filename = time() . '.' . $request->file('poster')->getClientOriginalExtension();
        $poster->save($path . $filename);
        $movie->poster = $filename;
    }
    
    /* If 'Meta Title' is empty, then fill it with the name of the movie */
    if ( empty($movie->seo_title) ) {
        $movie->seo_title = $movie->title;
    }
    
    /* If 'Meta Description' is empty, then fill it with the description of the movie */
    if ( empty($movie->seo_description) ) {
        $movie->seo_description = $movie->description;
    }
    
    // Apply all changes
    $movie->save();
    
    /* Parsing comma separated string of genres
     * and attaching them to movie */
    if (!empty($request->input('genres'))) {
    
        $genres = explode(',', $request->input('genres'));
    
        foreach($genres as $item) {
            $name = mb_strtolower(trim($item), 'UTF-8');
    
            $genre = Genre::where('name', $name)->first();
    
            /* If such genre doesn't exists in 'genres' table
             * then we create a new one */
            if ( empty($genre) ) {
                $genre = new Genre();
                $genre->fill(['name' => $name])->save();
            }
    
            $movie->genres()->attach($genre->id);
        }
    }
    
    /* Parsing comma separated string of countries
     * and attaching them to movie */
    if (!empty($request->input('countries'))) {
        $countries = explode(',', $request->input('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);
        }
    }
    
    /* Parsing comma separated string of directors
     * and attaching them to movie */
    if (!empty($request->input('directors'))) {
        $directors = explode(',', $request->input('directors'));
        foreach($directors as $item) {
            $name = mb_strtolower(trim($item), 'UTF-8');
    
            // Actors and Directors stored in the same table 'actors'
            $director = Actor::where('fullname', trim($name))->first();
    
            if ( empty($director) ) {
                $director = new Actor();
                $director->fill(['fullname' => $name])->save();
            }
            // Save this relation to 'movie_director' table
            $movie->directors()->attach($director->id);
        }
    }
    
    /* Parsing comma separated string of actors
     * and attaching them to movie */
    if (!empty($request->input('actors'))) {
    
        $actors = explode(',', $request->input('actors'));
        foreach($actors as $item) {
            $name = mb_strtolower(trim($item), 'UTF-8');
    
            $actor = Actor::where('fullname', $name)->first();
    
            if ( empty($actor) ) {
                $actor = new Actor();
                $actor->fill(['fullname' => $name])->save();
            }
    
            // Save this relation to 'movie_actor' table
            $movie->actors()->attach($actor->id);
        }
    }
    
    // Updating IMDB and Kinopoisk ratings
    if (!empty($movie->kinopoisk_id)) {
        $content = Curl::get('http://rating.kinopoisk.ru/'.$movie->kinopoisk_id.'.xml');
    
        $xml = new \SimpleXMLElement($content[0]->getContent());
    
        $movie->rating_kinopoisk = (double) $xml->kp_rating;
        $movie->rating_imdb = (double) $xml->imdb_rating;
        $movie->num_votes_kinopoisk = (int) $xml->kp_rating['num_vote'];
        $movie->num_votes_imdb = (int) $xml->imdb_rating['num_vote'];
    
        $movie->save();
    }
    
    return redirect('/admin/movies');
    }
    
    Run Code Online (Sandbox Code Playgroud)

man*_*nix 11

如果需要在其他类或项目模块中使用它,您需要考虑如何重用代码.首先,您可以这样做:

电影模型,可以改进以便:

  • 管理如何设置属性的方式
  • 在函数中创建好的函数包括/管理关系数据

看看Movie如何实现这些功能:

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){ ... }
}
Run Code Online (Sandbox Code Playgroud)

海报,您可以考虑使用服务提供商(我将展示此示例,因为我不知道您的Poster模型看起来像):

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;
    }
}
Run Code Online (Sandbox Code Playgroud)

配置文件 尝试使用配置文件存储相关的应用程序常量/数据,例如,存储电影图像路径:

'images' => storage_path() . '/images/movies/';
Run Code Online (Sandbox Code Playgroud)

现在,您可以$path = config('app.images');全球拨打电话.如果您只需要更改路径设置,则需要配置文件.

控制器作为注入类.最后,控制器用作只需要注入代码的类:

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');
}
Run Code Online (Sandbox Code Playgroud)