Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

mstnorris's avatar

Where is your create method?

This is your PostsController

<?php namespace App\Http\Controllers;

use View;
use Auth;
use Input;
use Illuminate\Http\Request;
use App\Post;

class PostController extends Controller{
    
    public function edit(Request $request, $id){
        $post = Post::find($id);
        
        $view = View::make('postedit', array(
            'post' => $post,
        ));
        return $view;
    }
    
    public function update(Request $request, $id){
        #$fields = $request->except(['_token']);
        $fields = Input::except('_token');
        #$fields = $request->only(array('title', 'content'));
        
        #dd($fields);
        
        Post::where('id', $id)->update($fields);
        
        $response = redirect()->route('post.edit', array('id' => $id));
        
        return $response;
    }
    
}
bobbybouwmann's avatar

The seeder always works because of this line

// database\seeds\DatabaseSeeder.php

Model::unguard();

This line makes sure you can seed all tables without MassAssignErrors ;)

TheFox's avatar

@mstnorris I just installed this Laravel instance. There is no create method. I added the posts via the seeder. Or manually with Sequel Pro.

JarekTkaczyk's avatar
Level 53

Guys, the problem here is not fillable, guarded or whatever else in the model, but the difference here:

$model = Model::find($id);
$model->update(Input::all()); // safe

Model::where('id', $id)->update(Input::all()); // BAD

First is eloquent method, latter is query builder method that doesn't care about fillable/guarded attributes.

That said, it's perfectly fine to pass Input::all() to update, save or new Model(..) as long as you define fillable on the model. But mind the difference between update on the model and on the builder as above.

A few more notes - I suggest you never use guarded, but always use fillable on your models.

Never use both guarded and fillable, because it makes no sense at all.

5 likes
TheFox's avatar

@blackbird Ok, I see, the seeder is an exception. But why does it work without any error through HTML inputs?

jekinney's avatar

@JarekTkaczyk

Reason I stated arguably best practice is input only to insure a field that is allowed for mass assignment (think user password off the top of my head) isn't updated by a user forcing the passing of a password into an update method with input all instead of a just updating a user name.... User password got changed.

Where I work, the QA department hacks and jacks into apps before release. So for the example above most apps don't allow even the "super Admin" to change a user's password. It can be accomplished very easily if you blindly pass what ever data is supplied into a method, and guess who has to update all the methods that allow input all()???

Of course each to his/her own, but you can't dis-guard an opinion :)

1 like
JarekTkaczyk's avatar

@jekinney I uderstand what you mean and I agree that it's our job to make sure we allow only what we want/can handle, especially when it's about user's input.

I personally restrict these fields, not necesarrily by using Input::only but it doesn't matter in the end.

Now, I always say, there are many paths to choose. One of them is picking only some fields, other is preparing your model correctly and knowing how to work with it. Let take a look at this super basic example:

// User model
protected $fillable = ['email', 'name'];


// controller
public function update($id)
{
    $user = User::findOrFail($id);

    // validate the input here, use Request to do the job or whatever you like

    $user->update(Input::all());

    return view('some_view')->with('notice', 'user updated');
}

Now, no matter what your QA team does with the FORM being passed here, only name and email will be updated.

1 like
ChristopherSFSD's avatar

I'm facing something similar here. When I manually test in browser, I have no problems. But when I run phpunit or behat, when records are created, the SQL that's generated includes ALL input and ignores the $fillable array.

What I have resorted to is changing my create function in my base repository from ...

    public function create(array $input)
    {
        return $this->model->create($input);
    }

To ...

    public function create(array $input)
    {
        $this->model->fill($input)->save();

        return $this->model;
    }

Any idea why I would have to do this to accommodate behat and phpunit?

UPDATE:

That didn't fully work either so I had to modify the create() function in my base repository as follows ...

    public function create(array $input)
    {
        if ( ! empty($this->model->fillable))
        {
            $input = array_intersect_key($input, array_flip($this->model->fillable));
        }

        return $this->model->create($input);
    }

Additionally I had to create a getFillableAttribute() method in my base model since $fillable is a protected property.

Again I'm completely lost as to why I should even have to be doing this. Shouldn't $fillable be automatically be honored when running my phpunit and behat tests?

Previous

Please or to participate in this conversation.