MassAssignmentException à Laravel


108

Je suis un débutant à Laravel. Je veux amorcer ma base de données. Lorsque j'exécute la commande seed, j'obtiens une exception

  [Illuminate\Database\Eloquent\MassAssignmentException]
  username



db:seed [--class[="..."]] [--database[="..."]]

Qu'est-ce que je fais mal. La commande que j'utilise est:

php artisan db:seed --class="UsersTableSeeder"

Ma classe de semences est la suivante:

class UsersTableSeeder extends Seeder {
    public function run()
    {
            User::truncate();
            User::create([
                'username' => 'PaulSheer',
                'email' => 'psheer@rute.co.za',
                'password' => '45678'
            ]);

            User::create([
                'username' => 'Stevo',
                'email' => 'steve@rute.co.za',
                'password' => '45678'
            ]);
    }
}

Réponses:


231

Lisez cette section du document Laravel: http://laravel.com/docs/eloquent#mass-assignment

Laravel fournit par défaut une protection contre les problèmes de sécurité des affectations de masse. C'est pourquoi vous devez définir manuellement les champs pouvant être "affectés en masse":

class User extends Model
{
    protected $fillable = ['username', 'email', 'password'];
}

Attention: soyez prudent lorsque vous autorisez l'affectation en masse de champs critiques comme passwordou role. Cela pourrait entraîner un problème de sécurité, car les utilisateurs pourraient être en mesure de mettre à jour les valeurs de ces champs lorsque vous ne le souhaitez pas.


7
-1 Bien que cela fonctionne, la solution de Pascalculator est meilleure en ce sens qu'elle ne se dé-protège que lorsque l'affectation en masse est nécessaire et non pour la durée de vie de l'application.
emragins

1
Vous avez raison, dans le contexte spécifique de l'amorçage de la base de données, il devrait être préférable de ne le déprotéger que pendant l'amorçage. Mais, comme cette réponse semble devenir un sujet de référence MassAssignmentExceptionet parce qu'elle pense que ma réponse est une bonne solution générique, je la garderai telle quelle.
Alexandre Butynski

Alexandre, j'ai du mal à suivre votre logique. Si vous êtes d'accord, vous pourriez tout aussi bien modifier votre propre réponse, d'autant plus qu'elle devient un sujet de référence. La réponse que vous avez suggérée fonctionnera effectivement, mais n'est pas conforme à la convention de Laravel.
Pascalculator

4
Je garde ma réponse telle quelle car je pense que c'est un bon modèle général (je l'utilise dans mes projets) et parce que je pense que ce n'est pas plus ou moins conforme à la convention de Laravel que votre réponse (voir la doc). Mais, parce que la pluralité des opinions est grande et que votre solution peut être aussi bonne que la mienne, je l'ai votée et j'encourage les autres à la lire :)
Alexandre Butynski

'password' => bcrypt ('45678')
Douglas.Sesar

31

J'utilise Laravel 4.2.

l'erreur que vous voyez

[Illuminate\Database\Eloquent\MassAssignmentException]
username

C'est en effet parce que la base de données est protégée contre le remplissage en masse, ce que vous faites lorsque vous exécutez un semeur. Cependant, à mon avis, il n'est pas nécessaire (et peut ne pas être sûr) de déclarer les champs qui doivent être remplis dans votre modèle si vous avez seulement besoin d'exécuter un semoir.

Dans votre dossier d'amorçage, vous avez la classe DatabaseSeeder:

class DatabaseSeeder extends Seeder {

    /**
    * Run the database seeds.
    *
    * @return void
    */

    public function run()
    {
        Eloquent::unguard();

        //$this->call('UserTableSeeder');
    }
}

Cette classe agit comme une façade, listant tous les seeders qui doivent être exécutés. Si vous appelez manuellement le semoir UsersTableSeeder via artisan, comme vous l'avez fait avec la php artisan db:seed --class="UsersTableSeeder"commande, vous contournez cette classe DatabaseSeeder.

Dans cette classe DatabaseSeeder, la commande Eloquent::unguard();permet une affectation en masse temporaire sur toutes les tables, ce qui est exactement ce dont vous avez besoin lorsque vous amorcez une base de données. Cette méthode non protégée n'est exécutée que lorsque vous exécutez la php aristan db:seedcommande, elle est donc temporaire par opposition à rendre les champs remplissables dans votre modèle (comme indiqué dans les réponses acceptées et autres).

Tout ce que vous avez à faire est d'ajouter la $this->call('UsersTableSeeder');à la méthode run dans la classe DatabaseSeeder et de l'exécuter php aristan db:seeddans votre CLI qui exécutera par défaut DatabaseSeeder.

Notez également que vous utilisez un nom de classe pluriel Utilisateurs, tandis que Laraval utilise la forme singulière Utilisateur. Si vous décidez de changer votre classe à la forme singulière conventionnelle, vous pouvez simplement décommenter le //$this->call('UserTableSeeder');qui a déjà été attribué mais commenté par défaut dans la classe DatabaseSeeder.


4
Pour les paranoïaques et les puristes: vous apprécierez également l'utilisation \Eloquent::reguard();, car une fois vos devoirs de masse terminés.
CenterOrbit

10

Pour rendre tous les champs remplissables , déclarez simplement sur votre classe:

protected $guarded = array();

Cela vous permettra d'appeler la méthode de remplissage sans déclarer chaque champ.


7

Ajoutez simplement Eloquent::unguard();en haut de la méthode run lorsque vous faites une graine, pas besoin de créer un $fillabletableau dans tous les modèles que vous devez amorcer.

Normalement, cela est déjà spécifié dans la DatabaseSeederclasse. Cependant, parce que vous appelez UsersTableSeederdirectement:

php artisan db:seed --class="UsersTableSeeder"

Eloquent::unguard(); n'est pas appelé et donne l'erreur.



1

J'obtenais l'exception MassAssignmentException quand j'ai étendu mon modèle comme ça.

class Upload extends Eloquent {

}

J'essayais d'insérer un tableau comme celui-ci

Upload::create($array);//$array was data to insert.

Le problème a été résolu lorsque j'ai créé le modèle de téléchargement en tant que

class Upload extends Eloquent {
    protected $guarded = array();  // Important
}

Référence https://github.com/aidkit/aidkit/issues/2#issuecomment-21055670


1

Modèle approprié à l'utilisateur dans votre fichier de contrôleur.

<?php
namespace App\Http\Controllers\Auth;
use App\Http\Controllers\Controller;
use App\User;

0

si vous avez une table et des champs sur la base de données, vous pouvez simplement utiliser cette commande:

php artisan db:seed --class=UsersTableSeeder --database=YOURDATABSE

0

Ce n'est pas un bon moyen lorsque vous souhaitez amorcer la base de données.
Utilisez faker au lieu du codage en dur, et avant tout cela, il vaut peut-être mieux tronquer les tables.

Prenons cet exemple:

    // Truncate table.  
    DB::table('users')->truncate();

    // Create an instance of faker.
    $faker = Faker::create();

    // define an array for fake data.
    $users = [];

    // Make an array of 500 users with faker.
    foreach (range(1, 500) as $index)
    {
        $users[] = [
            'group_id' => rand(1, 3),
            'name' => $faker->name,
            'company' => $faker->company,
            'email' => $faker->email,
            'phone' => $faker->phoneNumber,
            'address' => "{$faker->streetName} {$faker->postCode} {$faker->city}",
            'about' => $faker->sentence($nbWords = 20, $variableNbWords = true),
            'created_at' => new DateTime,
            'updated_at' => new DateTime,
        ];
    }

    // Insert into database.
    DB::table('users')->insert($users);

0

Utilisez le fillable pour indiquer à laravel quels champs peuvent être remplis à l'aide d'un tableau. Par défaut, Laravel n'autorise pas la mise à jour des champs de la base de données via un tableau

Protected $fillable=array('Fields you want to fill using array');

L'opposé de remplissable est guardable .


-1

Si vous utilisez la méthode d'insertion POO, vous n'avez pas à vous soucier des propriétés d'action de masse / remplissables:

$user = new User;
$user->username = 'Stevo';
$user->email = 'steve@rute.co.za';
$user->password = '45678';
$user->save();
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.