Tự học Laravel: (31) RELATIONSHIPS

This time, I would like to deal with the one-to-n relation in the model. As the user has multiple articles, associate the User model with the Article model.

MODEL

Associate User model and Article model with 1:n.

USER

// app/User.php
 
class User extends Authenticatable
{
    ...
    public function articles() 
    {
        return $this->hasMany('App\Article');
    }
}

Create an articles() method and associate it with Article in the hasMany() method.
Now you can get n Articles related to User as below.

$articles = User::find(1)->articles();

ARTICLE

// app/Article.php
 
class Article extends Model
{
    ...
    public function user() 
    {
        return $this->belongsTo('App\User');
    }
}

Create a user() method and associate it with the User in the belongsTo() method.
Now you can get one User associated with Article as below.

$user = Article::find(1)->user();

MIGRATION

Add a foreign key to the Users table to the Articles table. I would like to fix the migration file created earlier and roll back all DB and rebuild from the beginning.

<?php
// database/migrations/YYYY_MM_DD_TTTTTT_create_articles_table.php
 
...
 
class CreateArticlesTable extends Migration
{
    public function up()
    {
        Schema::create('articles', function(Blueprint $table)
        {
            $table->increments('id');
            $table->unsignedInteger('user_id'); 
            $table->string('title');
            $table->text('body');
            $table->timestamps();
 
            $table->foreign('user_id')
                ->references('id')
                ->on('users')
                ->onDelete('cascade');
        });
    }
 
    public function down()
    {
        Schema::dropIfExists('articles');
    }
}

user_id has been added as a foreign key. We specified onDelete(‘cascade’) as the foreign key constraint, and specified that if the data of the parent record Users is deleted, the data of the child records Articles is also deleted.

Now, roll back all DBs with the artistic command as follows, and execute all migration again. Please note that all data will be lost.

php artisan migrate:refresh

If you get the following error here, please add doctrine/dbal in composer. Migration will be possible after addition. This seems to be the case when using sqlite for DB.

Symfony\Component\Debug\Exception\FatalThrowableError : Class ‘Doctrine\DBAL\Driver\PDOSqlite\Driver’ not found

composer require doctrine/dbal

php artisan migrate:refresh

SEED

As the Articles table changes, the Seed is also corrected.

ADD USERSTABLESEEDER

Add UsersTableSeeder.php.

<?php
// database/seeds/UsersTableSeeder.php
 
use Illuminate\Database\Seeder;
 
class UsersTableSeeder extends Seeder
{
    public function run()
    {
        DB::table('users')->delete();
 
        App\User::create([
            'name' => 'root',
            'email' => 'root@example.com',
            'password' => Hash::make('password'),
        ]);
    }
}

DATABASESEEDER FIXES

Add a call to UsersTableSeeder.

<?php
// database/seeds/DatabaseSeeder.php
 
use Illuminate\Database\Seeder;
 
class DatabaseSeeder extends Seeder
{
    public function run()
    {
        $this->call([
            UsersTableSeeder::class,
            ArticlesTableSeeder::class,
        ]);
    }
}

ARTICLEFACTORY FIX

Add a user_id item.

<?php
// database/factories/ArticleFactory.php
 
use Faker\Generator as Faker;
use Carbon\Carbon;
 
$factory->define(App\Article::class, function (Faker $faker) {
    return [
        'title' => $faker->sentence(),
        'body' => $faker->paragraph(),
        'published_at' => Carbon::today(),     
        'user_id' => function () {
            return factory(App\User::class)->create()->id;
        },
    ];
});

At present, one User is created each time an Article is created.

CORRECTION OF ARTICLESTABLESEEDER

<?php
// database/seeds/ArticlesTableSeeder.php
 
use Illuminate\Database\Seeder;
 
class ArticlesTableSeeder extends Seeder
{
    public function run()
    {
        DB::table('articles')->delete(); 
        $user = App\User::first(); 
        factory(App\Article::class, 20)->create([ 
            'user_id' => $user->id,
        ]);
    }
}

After getting one user, I associate Article with that user and create it.

By passing an associative array of item names and values ​​to the create() method of factory, you can overwrite the settings of the items defined in factory. According to the definition content of ArticleFactory, a user is created for each Article and set user_id, but it is overwritten and the ID of the searched user is set.

SEEDING

Run seed with the artisan command.

php artisan db:seed

Now we have prepared the Article data for testing as data associated with the user.

CONTROLLER

Modify the new article to be saved as the logged-in user’s article.

// app/Http/Controllers/ArticlesController.php
 
...
 
use Illuminate\Support\Facades\Auth;
 
class ArticlesController extends Controller {
    ...
    public function store(ArticleRequest $request) {
        // Article::create($request->validated());
        Auth::user()->articles()->create($request->validated());
 
        return redirect()->route('articles.index')
            ->with('message', 'Create Successful');
    }
    ...
}

ACTION CONFIRMATION

After logging in and creating a new article, check the data with tinker. Please register
new users from http://localhost:8000/auth/register and try variously.

$ php artisan tinker
>>>
>>> $user = App\User::where("name", "who")->first();
>>>
>>> $user->articles->count();
=> 2
>>>
>>> $user->articles->toArray();
=> [
       [
           "id"           => "11",
           "user_id"      => "5",
           "title"        => "WHOの記事",
           "body" => "This is rn only",
           "created_at"   => "2015-03-24 11:56:17",
           "updated_at"   => "2015-03-24 11:56:17",
           "published_at" => "2015-03-24 00:00:00"
       ],
       [
           "id"           => "12",
           "user_id"      => "5",
           "title" => "WHO second article",
           "body"         => "foornbar",
           "created_at"   => "2015-03-24 12:05:31",
           "updated_at"   => "2015-03-24 12:05:31",
           "published_at" => "2015-03-24 00:00:00"
       ]
   ]
>>>
>>>
>>> $article = App\Article::find(11);
>>>
>>> $article->user->toArray();
=> [
       "id"         => "5",
       "name"       => "who",
       "email"      => "who@sample.com",
       "created_at" => "2015-03-24 11:55:55",
       "updated_at" => "2015-03-24 11:55:55"
   ]
>>> 
  • Articles were accessed from the user model at $user->articles.
  • I could access the user model from the article model at $article->user.

SUMMARY

You can use hasMany() and belongsTo() to create a one-to-n relation between models.

Eloquent relations include one-to-one and n-to-n in addition to one-to-n, so please read on the official site.

http://laravel.com/docs/master/eloquent-relationships

Leave a Reply

Your email address will not be published.

This site uses Akismet to reduce spam. Learn how your comment data is processed.