hassansaid's avatar

Using controller function for two different eloquent models

Hi everyone,

I am currently developing an application for an indy movie production company. The way I have the workflow right now, the user begins by creating a new movie object by entering the movie title and synopsis. From there the user can then add more details such as price, run-time, full-screen/wide-screen, etc. The movie basic (title, synopsis) are in one database table, and the details are in another. I have set up a one-to-one relationship between the two eloquent models. I have also set up a MovieController that allows me to very easily do CRUD operations on the movie basic model, and when I am displaying the movie object to the user, I can display both the basics and details.

What I was wondering was there some way to use the already existent functions in the movie controller to do CRUD operations on the movie details without having to create new functions in the controller? Also is it possible to reuse the views I've created for each corresponding CRUD operation? In other words can I would like

something.dev/cms/create

In one instance to match to creating a new movie (title, synopsis) and in another instance to match to creating the movie detail (price, run-time, full-screen/widescreen) etc. Is this possible? I have provide the code for the two models below:

<?php namespace App;

use Illuminate\Database\Eloquent\Model;

class Movie_basic extends Model {

    protected $fillable = ['movie_title', 'movie_synopsis'];

    protected $guarded = ['id'];

    public function details()
    {
        return $this->hasOne('App\Movie_detail', 'movie_id');
    }

    public function personnel()
    {
        return $this->hasMany('App\Movie_personnel', 'movie_id');
    }
}
<?php namespace App;

use Illuminate\Database\Eloquent\Model;

class Movie_detail extends Model {

    protected $fillable = ['minutes', 'languages', 'viewer_discretion', 'screen_type', 'price'];

    protected $guarded = ['id', 'movie_id'];

    public function basics()
    {
        return $this->belongsTo('App\Movie_basic');
    }

}
0 likes
8 replies
pixelpeter's avatar

I don't think this is te correct approach

If you have repeating functionality while selecting data from your models try query scopes http://laravel.com/docs/master/eloquent#query-scopes

If you have repeating functionality in your controller extract this to a service or repository https://laracasts.com/lessons/controller-cleanup https://laracasts.com/lessons/repositories-simplified

If you need to use the same data in your partials and views use View composers https://laracasts.com/series/laravel-5-fundamentals/episodes/25

zoransa's avatar

@pixelpeter it's my virtue but you gave more comprehensive answer.

Anyway, let's say you want to make concrete implementation on your repository you may do 'dependency injection' and pass your eloquent object or id of Movie and then attach details in dedicated method that come from array and you pass Request or however you feed data to the database.

pixelpeter's avatar

@zoransa If this is a question I didn't get it. Can you explain more what you mean with

Anyway, let's say you want to make concrete implementation on your repository you may do 'dependency injection' and pass your eloquent object or id of Movie and then attach details in dedicated method that come from array and you pass Request or however you feed data to the database.

hassansaid's avatar

Thanks for the answers guys. I still don't get how to reuse the same URL however though. By that I mean I would like something like:

www.something.com/1/edit

to at one point be a link to the edit movie's basic information and at another point be a link to edit the movie details. I ask this because the show method in my MovieController retrieves both the movie's basic and detailed information; via relationships, and displays them on the same page. I have an edit link for each section so a user can edit each individually. What I have tried so far is using this:

<h4>Movie Baiscs <span class="pull-right"><a href="{{ action('MovieController@edit', [$movie->id, "info_to_edit"]) }}">Edit</a></span></h4>

I essentially replace that 'info_to_edit' with either 'movie_basic' or 'movie_detail'. I intend to then say in the MovieController edit function that if 'info_to_edit' is 'movie_basic' call the repository using the movie basic model, if not call the repository using the movie detail model. However this strategy seems to fail with this error:

Missing argument 2 for App\Http\Controllers\MovieController::edit()

Would you guys know any better way of doing this? Also the method I described above produces a url like so:

www.something.com/1/edit?info_to_edit

Is there anyway to hide that 'info_to_edit' part of the link?

wing5wong's avatar

can you post your controller? also why hide the query string, if its useful to you to have it

hassansaid's avatar

@wing5wong Sorry for the late reply. My controller is below:

<?php namespace App\Http\Controllers;

//use App\Http\Requests;
use App\Http\Controllers\Controller;

//use Illuminate\Http\Request;

use App\Repositories\MovieBasicRepository as MovieBasic;
use App\Repositories\MovieDetailRepository as MovieDetail;
use App\Movie_basic;
use App\Movie_detail;
use App\Http\Requests\MovieBasicRequest;
use App\Http\Requests\MovieDetailRequest;

class MovieController extends Controller {

    /**
     * @var Movie
     */
    private $movieBasic, $movieDetail;
    private $request;

    public function __construct(MovieBasic $movieBasic, MovieDetail $movieDetail)
    {
        $this->movieBasic = $movieBasic;
        $this->movieDetail = $movieDetail;
    }

    /**
     * Display a listing of the resource.
     *
     * @return Response
     */
    public function index()
    {
        // List all movies
        //$movies = Movie_basic::oldest('movie_title')->get();
        $movies = $this->movieBasic->all();

        return view('cms.index', compact('movies'));
    }

    /**
     * Show the form for creating a new resource.
     *
     * @return Response
     */
    public function create()
    {
        return view('cms.create');
    }

    /**
     * Store a newly created resource in storage.
     *
     * @param MovieBasicRequest $request
     * @return Response
     */
    public function store(MovieBasicRequest $request)
    {
        Movie_basic::create($request->all());

        return redirect('cms');
    }

    /**
     * Display the specified resource.
     *
     * @param  int  $id
     * @return Response
     */
    public function show($id)
    {
        // view one particular movie
        $movie = $this->movieBasic->find($id);
        
        return view('cms.show', compact('movie'));
    }

    /**
     * Show the form for editing the specified resource.
     *
     * @param  int  $id
     * @return Response
     */
    public function edit($id)
    {
        $type = $_GET['type'];

        $movie = $this->movieBasic->find($id);
        
        return view('cms.edit', compact('movie', 'type'));
    }

    /**
     * Update the specified resource in storage.
     *
     * @param  int  $id, MovieBasicRequest $request
     * @return Response
     */
    public function update($id)
    {
        if(strcmp($_GET['type'], 'Movie_basic'))
        {
            $movie = $this->movieBasic->find($id);
            $this->movieBasic->update($id, MovieBasicRequest $this->request);
        }
                    
        return redirect()->action('MovieController@show', compact('movie'));
    }

    /**
     * Remove the specified resource from storage.
     *
     * @param  int  $id
     * @return Response
     */
    public function destroy($id)
    {
        Movie_basic::findOrFail($id)->delete();

        return redirect('cms');
    }

}

I got pass that previous issue now by having a $param array in the view and passing that to the action http helper. I however have another issue in that I am trying to re-use my update method but I don't know how to reuse it with the different Requests I have. I basically want to use requests to validate my input before updating, however when I try to do through the current code I get a:

FatalErrorException in MovieController.php line 106: syntax error, unexpected '$this' (T_VARIABLE)

Which is expected as it tries to resolve the MovieBasicRequest the the $this->request. I also tried using the new MovieBasicRequest and expectedly this resulted in no validation happening. Any ideas on how to use the Request objects?

Please or to participate in this conversation.