# Package spatie/menu full phần 1 (ok)

### Ví dụ để tham khảo full <https://github.com/spatie/spatie.be>

### Ví dụ 1: Chủ yếu biết cách sử dụng cơ bản

C:\xampp82\htdocs\lva1\routes\web.php

```php
Route::get('/home', [App\Http\Controllers\HomeController::class, 'index'])->name('home');
Route::get('/about', [App\Http\Controllers\HomeController::class, 'index'])->name('about');
Route::get('/contact', [App\Http\Controllers\HomeController::class, 'index'])->name('contact');
```

C:\xampp82\htdocs\lva1\app\Providers\AppServiceProvider.php

```php
public function boot(): void
  {
    Menu::macro('main', function () {
      return Menu::new()
        ->route('home', 'Home')
        ->route('about', 'About')
        ->route('contact', 'Contact');
    });
  }
```

C:\xampp82\htdocs\lva1\resources\views\welcome.blade.php

```blade
<header>
    {!! Menu::main() !!}
</header>
```

<figure><img src="https://1957079826-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MCBeDUD-PK_RF-YgJRe%2Fuploads%2FqzaUxj8PqhhOk8arZbSZ%2Fimage.png?alt=media&#x26;token=e0410d26-2516-44ae-8e6e-4dd3c700b769" alt=""><figcaption></figcaption></figure>

### Ví dụ 2: Ta đi nghiên cứu dùng cách xác thực kết hợp với menu

### Ví dụ 2.1: Kết hợp bảng [role\_user](https://localhost/phpmyadmin/index.php?route=/sql\&pos=0\&db=lva3\&table=role_user), [roles](https://localhost/phpmyadmin/index.php?route=/sql\&pos=0\&db=lva3\&table=roles), [users](https://localhost/phpmyadmin/index.php?route=/sql\&pos=0\&db=lva3\&table=users)

C:\xampp82\htdocs\lva3\database\migrations\2017\_12\_27\_235046\_create\_roles\_table.php

```php
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateRolesTable extends Migration
{
  /**
   * Run the migrations.
   *
   * @return void
   */
  public function up()
  {
    Schema::create('roles', function (Blueprint $table) {
      $table->increments('id');
      $table->string('name')->unique();
      $table->timestamps();
    });
  }
  /**
   * Reverse the migrations.
   *
   * @return void
   */
  public function down()
  {
    Schema::dropIfExists('roles');
  }
}

```

C:\xampp82\htdocs\lva3\database\migrations\2014\_10\_12\_000000\_create\_users\_table.php

```php
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
  /**
   * Run the migrations.
   */
  public function up(): void
  {
    Schema::create('users', function (Blueprint $table) {
      $table->id();
      $table->string('name');
      $table->string('email')->unique();
      $table->timestamp('email_verified_at')->nullable();
      $table->string('password');
      $table->rememberToken();
      $table->timestamps();
      $table->string('deleted_at')->nullable();
    });
  }
  /**
   * Reverse the migrations.
   */
  public function down(): void
  {
    Schema::dropIfExists('users');
  }
};

```

C:\xampp82\htdocs\lva3\database\migrations\2017\_12\_27\_235904\_create\_role\_user\_table.php

```php
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateRoleUserTable extends Migration
{
  /**
   * Run the migrations.
   *
   * @return void
   */
  public function up()
  {
    Schema::create('role_user', function (Blueprint $table) {
      $table->unsignedInteger('role_id');
      $table->unsignedInteger('user_id');
      $table->primary(['role_id', 'user_id']);
      // $table->foreign('role_id')
      //   ->references('id')
      //   ->on('roles')
      //   ->onDelete('cascade');
      // $table->foreign('user_id')
      //   ->references('id')
      //   ->on('users')
      //   ->onDelete('cascade');
    });
  }
  /**
   * Reverse the migrations.
   *
   * @return void
   */
  public function down()
  {
    Schema::dropIfExists('role_user');
  }
}
```

C:\xampp82\htdocs\lva3\database\factories\UserFactory.php

```php
<?php
namespace Database\Factories;
use Illuminate\Database\Eloquent\Factories\Factory;
use Illuminate\Support\Str;
/**
 * @extends \Illuminate\Database\Eloquent\Factories\Factory<\App\Models\User>
 */
class UserFactory extends Factory
{
  /**
   * Define the model's default state.
   *
   * @return array<string, mixed>
   */
  public function definition(): array
  {
    return [
      'name' => fake()->name(),
      'email' => fake()->unique()->safeEmail(),
      'email_verified_at' => now(),
      'password' => '$2y$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi', // password
      'remember_token' => Str::random(10),
    ];
  }
  /**
   * Indicate that the model's email address should be unverified.
   */
  public function unverified(): static
  {
    return $this->state(fn (array $attributes) => [
      'email_verified_at' => null,
    ]);
  }
}

```

C:\xampp82\htdocs\lva3\database\factories\RoleFactory.php

```php
<?php
namespace Database\Factories;
use Illuminate\Database\Eloquent\Factories\Factory;
class RoleFactory extends Factory
{
  /**
   * The name of the factory's corresponding model.
   *
   * @var string
   */
  protected $model = Role::class;
  /**
   * Define the model's default state.
   *
   * @return array
   */
  public function definition()
  {
    return [
      'slug' => $this->faker->unique()->word(),
    ];
  }
}

```

C:\xampp82\htdocs\lva3\database\seeders\DatabaseSeeder.php

```php
<?php
namespace Database\Seeders;
// use Illuminate\Database\Console\Seeds\WithoutModelEvents;
use Illuminate\Database\Seeder;
class DatabaseSeeder extends Seeder
{
  /**
   * Seed the application's database.
   */
  public function run(): void
  {
    $this->call(RolesTableSeeder::class);
    $this->call(UsersTableSeeder::class);
  }
}

```

C:\xampp82\htdocs\lva3\database\seeders\UsersTableSeeder.php

```php
<?php
namespace Database\Seeders;
use App\Models\Role;
use App\Models\User;
use Illuminate\Database\Seeder;
class UsersTableSeeder extends Seeder
{
  /**
   * Run the database seeds.
   *
   * @return void
   */
  public function run()
  {
    $admin = Role::where('name', 'admin')->first();
    $curator = Role::where('name', 'curator')->first();
    User::factory()->create([
      'email' => 'nen.zivanovic@gmail.com',
    ])->roles()->sync([$admin->id, $curator->id]);
    User::factory()->create([
      'email' => 'admin@example.com',
    ])->roles()->sync([$admin->id]);
    User::factory()->create([
      'email' => 'curator@example.com',
    ])->roles()->sync([$curator->id]);
    User::factory()->create([
      'email' => 'member@example.com',
    ]);
  }
}
```

C:\xampp82\htdocs\lva3\database\seeders\RolesTableSeeder.php

```php
<?php
namespace Database\Seeders;
use App\Models\Role;
use Illuminate\Database\Seeder;
class RolesTableSeeder extends Seeder
{
  protected $roles = [
    'admin',
    'curator',
  ];
  /**
   * Run the database seeds.
   *
   * @return void
   */
  public function run()
  {
    foreach ($this->roles as $role) {
      Role::firstOrCreate(['name' => $role]);
    }
  }
}

```

C:\xampp82\htdocs\lva3\app\Models\User.php

```php
<?php
namespace App\Models;
// use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Laravel\Sanctum\HasApiTokens;
use Illuminate\Database\Eloquent\SoftDeletes;
use App\Concerns\HasRoles;
class User extends Authenticatable
{
  use HasApiTokens, HasFactory, Notifiable, SoftDeletes, HasRoles;
  /**
   * The attributes that are mass assignable.
   *
   * @var array<int, string>
   */
  protected $fillable = [
    'name',
    'email',
    'password',
  ];
  /**
   * The attributes that should be hidden for serialization.
   *
   * @var array<int, string>
   */
  protected $hidden = [
    'password',
    'remember_token',
  ];
  /**
   * The attributes that should be cast.
   *
   * @var array<string, string>
   */
  protected $casts = [
    'email_verified_at' => 'datetime',
  ];
}

```

C:\xampp82\htdocs\lva3\app\Models\Role.php

```php
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Role extends Model
{
  use HasFactory;
  /**
   * The attributes that are mass assignable.
   *
   * @var array
   */
  protected $fillable = ['name'];
  /**
   * Find role by it's name.
   *
   * @param  string  $name
   * @return self
   */
  public static function findByName($name)
  {
    return static::where('name', $name)->first();
  }
  /**
   * Find all roles that have given names.
   *
   * @param  array|string  $names
   * @return \Illuminate\Database\Eloquent\Collection
   */
  public static function findAllByName($names)
  {
    return static::whereIn('name', $names)->get();
  }
}

```

C:\xampp82\htdocs\lva3\app\Concerns\HasRoles.php

```php
<?php
namespace App\Concerns;
use App\Models\Role;
trait HasRoles
{
  /**
   * Relation to roles that the user has.
   *
   * @return \Illuminate\Database\Eloquent\Relations\BelongsToMany
   */
  public function roles()
  {
    return $this->belongsToMany(Role::class);
  }
  /**
   * Scope the query to get only users with role of curator.
   *
   * @param  \Illuminate\Database\Eloquent\Builder  $query
   * @return \Illuminate\Database\Eloquent\Builder
   */
  public function scopeAdmins($query)
  {
    return $query->whereHas('roles', function ($query) {
      return $query->where('name', 'admin');
    });
  }
  /**
   * Scope the query to get only users with role of curator.
   *
   * @param  \Illuminate\Database\Eloquent\Builder  $query
   * @return \Illuminate\Database\Eloquent\Builder
   */
  public function scopeCurators($query)
  {
    return $query->whereHas('roles', function ($query) {
      return $query->where('name', 'curator');
    });
  }
  /**
   * Get names of roles the user has.
   *
   * @return \Illuminate\Support\Collection
   */
  protected function roleNames()
  {
    return $this->roles->pluck('name');
  }
  /**
   * Check if user has given role.
   *
   * @param  string  $role
   * @return bool
   */
  public function hasRole($role)
  {
    return $this->roleNames()->contains($role);
  }
  /**
   * Check if user has one or more of the given roles.
   *
   * @param  array  $roles
   * @return bool
   */
  public function hasAnyRole(array $roles)
  {
    return $this->roleNames()->intersect($roles)->isNotEmpty();
  }
  /**
   * Check if user has all the given roles.
   *
   * @param  array  $roles
   * @return bool
   */
  public function hasAllRoles(array $roles)
  {
    return count($roles) === $this->roleNames()->intersect($roles)->count();
  }
  /**
   * Assign given roles to user.
   *
   * @param  array|string  $roles
   * @return $this
   */
  public function assignRoles($roles)
  {
    if (is_string($roles)) {
      $roles = func_get_args();
    }
    $this->roles()->attach(Role::findAllByName($roles));
    return $this->load('roles');
  }
  /**
   * Revoke given roles to user.
   *
   * @param  array|string  $roles
   * @return $this
   */
  public function revokeRoles($roles)
  {
    if (is_string($roles)) {
      $roles = func_get_args();
    }
    $this->roles()->detach(Role::findAllByName($roles));
    return $this->load('roles');
  }
}

```

<figure><img src="https://1957079826-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MCBeDUD-PK_RF-YgJRe%2Fuploads%2FaBTJZ8cEaxXZP7atNPuN%2Fimage.png?alt=media&#x26;token=478606f0-5fd2-43cf-8a1b-eba5e790883d" alt=""><figcaption></figcaption></figure>

<figure><img src="https://1957079826-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MCBeDUD-PK_RF-YgJRe%2Fuploads%2FqUoWF4FqlUI1Gg20WbPL%2Fimage.png?alt=media&#x26;token=2a585c78-b7dd-4f34-a47a-259259026035" alt=""><figcaption></figcaption></figure>

<figure><img src="https://1957079826-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MCBeDUD-PK_RF-YgJRe%2Fuploads%2FdlEADHBLv97e8jLtDXYe%2Fimage.png?alt=media&#x26;token=6ffdcc01-56aa-46e8-a41c-dd26ad40c73a" alt=""><figcaption></figcaption></figure>

###

{% file src="<https://1957079826-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MCBeDUD-PK_RF-YgJRe%2Fuploads%2FsGKbAzYY6iR4keH5GwcX%2Flva3.zip?alt=media&token=9eea366b-9737-4c64-90c2-d54641f501ea>" %}

### Ví dụ 2.2: Áp dụng role\_user, roles, users

<figure><img src="https://1957079826-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MCBeDUD-PK_RF-YgJRe%2Fuploads%2FBL5MZDMXqOn3kvSM8Z8V%2Fimage.png?alt=media&#x26;token=4b432c2a-6506-43a6-bb2b-830d00c53c45" alt=""><figcaption></figcaption></figure>

<figure><img src="https://1957079826-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MCBeDUD-PK_RF-YgJRe%2Fuploads%2FxwGLzOGc8w1Urae7UQ3G%2Fimage.png?alt=media&#x26;token=05a372ca-a093-48e6-8a6a-9e9dded23392" alt=""><figcaption></figcaption></figure>

<figure><img src="https://1957079826-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MCBeDUD-PK_RF-YgJRe%2Fuploads%2F7JB2i6IEqQAL7i9KgerL%2Fimage.png?alt=media&#x26;token=d3978a84-55d0-444a-a5c6-43bb3d27c783" alt=""><figcaption></figcaption></figure>

<figure><img src="https://1957079826-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MCBeDUD-PK_RF-YgJRe%2Fuploads%2FVDyZOKvjHKQlvNityX4f%2Fimage.png?alt=media&#x26;token=ffdf68b1-b823-47c1-9d63-9faf54b5e772" alt=""><figcaption></figcaption></figure>

<figure><img src="https://1957079826-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MCBeDUD-PK_RF-YgJRe%2Fuploads%2FduYFhrLuj9rjquC8f4XX%2Fimage.png?alt=media&#x26;token=3942fd3c-a2d1-412f-9fac-f428df6ad306" alt=""><figcaption></figcaption></figure>

###

{% file src="<https://1957079826-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MCBeDUD-PK_RF-YgJRe%2Fuploads%2FyfhtI99eyY6RB8ODGw5a%2Flva5.zip?alt=media&token=a17e79e1-7403-4fe5-99aa-0a113ed431ef>" %}

### Ví dụ 2.3: Tạo tài khoản và xác thực 😀&#x20;

<figure><img src="https://1957079826-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MCBeDUD-PK_RF-YgJRe%2Fuploads%2FzUkI8Loxb3eipMUeMgUA%2Fimage.png?alt=media&#x26;token=3d742d70-006f-425c-8bee-1ae421036f7b" alt=""><figcaption></figcaption></figure>

C:\xampp82\htdocs\lva7\config\livewire.php

```php
'layout' => 'layouts.app',

```

C:\xampp82\htdocs\lva7\resources\views\layouts\app.blade.php

```blade
<!doctype html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <!-- CSRF Token -->
  <meta name="csrf-token" content="{{ csrf_token() }}">
  <title>{{ config('app.name', 'Laravel') }}</title>
  <!-- Fonts -->
  <link rel="dns-prefetch" href="//fonts.gstatic.com">
  <!-- Scripts -->
  @vite(['resources/sass/app.scss', 'resources/js/app.js'])
</head>
<body>
  <div id="app">
    <nav class="navbar navbar-expand-md navbar-light bg-white shadow-sm">
      <div class="container">
        {!! Menu::app() !!}
        <a class="navbar-brand" href="{{ url('/') }}">
          {{ config('app.name', 'Laravel') }}
        </a>
        <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarSupportedContent"
          aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="{{ __('Toggle navigation') }}">
          <span class="navbar-toggler-icon"></span>
        </button>
        <div class="collapse navbar-collapse" id="navbarSupportedContent">
          <!-- Left Side Of Navbar -->
          <ul class="navbar-nav me-auto">
          </ul>
          <!-- Right Side Of Navbar -->
          <ul class="navbar-nav ms-auto">
            <!-- Authentication Links -->
            @guest
            @if (Route::has('login'))
            <li class="nav-item">
              <a class="nav-link" href="{{ route('login') }}">{{ __('Login') }}</a>
            </li>
            @endif
            @if (Route::has('register'))
            <li class="nav-item">
              <a class="nav-link" href="{{ route('register') }}">{{ __('Register') }}</a>
            </li>
            @endif
            @else
            <li class="nav-item dropdown">
              <a id="navbarDropdown" class="nav-link dropdown-toggle" href="#" role="button" data-bs-toggle="dropdown"
                aria-haspopup="true" aria-expanded="false" v-pre>
                {{ Auth::user()->name }}
              </a>
              <div class="dropdown-menu dropdown-menu-end" aria-labelledby="navbarDropdown">
                <a class="dropdown-item" href="{{ route('logout') }}" onclick="event.preventDefault();
                                                     document.getElementById('logout-form').submit();">
                  {{ __('Logout') }}
                </a>
                <form id="logout-form" action="{{ route('logout') }}" method="POST" class="d-none">
                  @csrf
                </form>
              </div>
            </li>
            @endguest
          </ul>
        </div>
      </div>
    </nav>
    <main class="py-4">
      @yield('content')
      {{ $slot }}
    </main>
  </div>
</body>
</html>

```

C:\xampp82\htdocs\lva7\database\factories\ArticleFactory.php

```php
<?php
namespace Database\Factories;
use App\Models\Article;
use Illuminate\Database\Eloquent\Factories\Factory;
class ArticleFactory extends Factory
{
  /**
   * The name of the factory's corresponding model.
   *
   * @var string
   */
  protected $model = Article::class;
  /**
   * Define the model's default state.
   *
   * @return array
   */
  public function definition()
  {
    return [
      'title' => fake()->text(60),
      'body' => fake()->text(1500),
      'description' => fake()->text(150),
    ];
  }
}

```

C:\xampp82\htdocs\lva7\database\factories\CommentFactory.php

```php
<?php
namespace Database\Factories;
use App\Models\Comment;
use Illuminate\Database\Eloquent\Factories\Factory;
class CommentFactory extends Factory
{
  /**
   * The name of the factory's corresponding model.
   *
   * @var string
   */
  protected $model = Comment::class;
  /**
   * Define the model's default state.
   *
   * @return array
   */
  public function definition()
  {
    return [
      'body' => fake()->text(),
      'article_id' => fake()->randomElement(range(1, 50)),
      'user_id' => fake()->randomElement(range(1, 10)),
    ];
  }
}

```

C:\xampp82\htdocs\lva7\database\factories\TagFactory.php

```php
<?php
namespace Database\Factories;
use App\Models\Tag;
use Illuminate\Database\Eloquent\Factories\Factory;
class TagFactory extends Factory
{
  /**
   * The name of the factory's corresponding model.
   *
   * @var string
   */
  protected $model = Tag::class;
  /**
   * Define the model's default state.
   *
   * @return array
   */
  public function definition()
  {
    return [
      'name' => fake()->unique()->lexify('?????'),
    ];
  }
}

```

C:\xampp82\htdocs\lva7\database\factories\UserFactory.php

```php
<?php
namespace Database\Factories;
use App\Models\User;
use Illuminate\Database\Eloquent\Factories\Factory;
use Illuminate\Support\Str;
class UserFactory extends Factory
{
  /**
   * The name of the factory's corresponding model.
   *
   * @var string
   */
  protected $model = User::class;
  /**
   * Define the model's default state.
   *
   * @return array
   */
  public function definition()
  {
    return [
      'name' => fake()->name(),
      'email' => fake()->unique()->safeEmail(),
      'email_verified_at' => now(),
      'password' => '$2y$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi', // password
      'remember_token' => Str::random(10),
      'username' => fake()->unique()->userName,
      'image' => fake()->imageUrl(),
      'bio' => fake()->text(),
    ];
  }
  /**
   * Indicate that the model's email address should be unverified.
   *
   * @return \Illuminate\Database\Eloquent\Factories\Factory
   */
  public function unverified()
  {
    return $this->state(function (array $attributes) {
      return [
        'email_verified_at' => null,
      ];
    });
  }
}

```

C:\xampp82\htdocs\lva7\database\migrations\2014\_10\_12\_000000\_create\_users\_table.php

```php
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
  /**
   * Run the migrations.
   */
  public function up(): void
  {
    Schema::create('users', function (Blueprint $table) {
      $table->id();
      $table->string('name');
      $table->string('email')->unique();
      $table->timestamp('email_verified_at')->nullable();
      $table->string('password');
      $table->string('username')->unique();
      $table->text('bio')->nullable();
      $table->text('image')->nullable();
      $table->rememberToken();
      $table->timestamps();
    });
  }
  /**
   * Reverse the migrations.
   */
  public function down(): void
  {
    Schema::dropIfExists('users');
  }
};

```

C:\xampp82\htdocs\lva7\database\migrations\2021\_05\_18\_103101\_create\_articles\_table.php

```php
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
  /**
   * Run the migrations.
   *
   * @return void
   */
  public function up()
  {
    Schema::create('articles', function (Blueprint $table) {
      $table->id();
      $table->string('title');
      $table->string('slug')->nullable();
      $table->text('description')->nullable();
      $table->text('body');
      $table->foreignId('user_id')->constrained();
      $table->timestamps();
    });
  }
  /**
   * Reverse the migrations.
   *
   * @return void
   */
  public function down()
  {
    Schema::dropIfExists('articles');
  }
};

```

C:\xampp82\htdocs\lva7\database\migrations\2021\_05\_18\_103506\_create\_tags\_table.php

```php
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
  /**
   * Run the migrations.
   *
   * @return void
   */
  public function up()
  {
    Schema::create('tags', function (Blueprint $table) {
      $table->id();
      $table->string('name');
      $table->string('slug')->nullable();
      $table->timestamps();
    });
  }
  /**
   * Reverse the migrations.
   *
   * @return void
   */
  public function down()
  {
    Schema::dropIfExists('tags');
  }
};

```

C:\xampp82\htdocs\lva7\database\migrations\2021\_05\_18\_103540\_create\_comments\_table.php

```php
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
  /**
   * Run the migrations.
   *
   * @return void
   */
  public function up()
  {
    Schema::create('comments', function (Blueprint $table) {
      $table->id();
      $table->text('body');
      $table->foreignId('article_id')->constrained();
      $table->foreignId('user_id')->constrained();
      $table->timestamps();
    });
  }
  /**
   * Reverse the migrations.
   *
   * @return void
   */
  public function down()
  {
    Schema::dropIfExists('comments');
  }
};

```

C:\xampp82\htdocs\lva7\database\migrations\2021\_05\_18\_103859\_create\_article\_tag\_table.php

```php
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
  /**
   * Run the migrations.
   *
   * @return void
   */
  public function up()
  {
    Schema::create('article_tag', function (Blueprint $table) {
      $table->id();
      $table->foreignId('article_id')->constrained();
      $table->foreignId('tag_id')->constrained();
    });
  }
  /**
   * Reverse the migrations.
   *
   * @return void
   */
  public function down()
  {
    Schema::dropIfExists('article_tag');
  }
};

```

C:\xampp82\htdocs\lva7\database\seeders\ArticleSeeder.php

```php
<?php
namespace Database\Seeders;
use App\Models\Article;
use App\Models\User;
use Illuminate\Database\Seeder;
class ArticleSeeder extends Seeder
{
  /**
   * Run the database seeds.
   *
   * @return void
   */
  public function run()
  {
    User::factory(10)->has(Article::factory()->count(10))->create();
  }
}
```

C:\xampp82\htdocs\lva7\database\seeders\ArticleTagSeeder.php

```php
<?php
namespace Database\Seeders;
use App\Models\Article;
use App\Models\Tag;
use Illuminate\Database\Seeder;
class ArticleTagSeeder extends Seeder
{
  /**
   * Run the database seeds.
   *
   * @return void
   */
  public function run()
  {
    foreach (Article::all() as $article) {
      $article->tags()->attach(Tag::all()->random());
    }
  }
}

```

C:\xampp82\htdocs\lva7\database\seeders\CommentSeeder.php

```php
<?php
namespace Database\Seeders;
use App\Models\Comment;
use Illuminate\Database\Seeder;
class CommentSeeder extends Seeder
{
  public function run()
  {
    Comment::factory(50)->create();
  }
}

```

C:\xampp82\htdocs\lva7\database\seeders\TagSeeder.php

```php
<?php
namespace Database\Seeders;
use App\Models\Tag;
use Illuminate\Database\Seeder;
class TagSeeder extends Seeder
{
  /**
   * Run the database seeds.
   *
   * @return void
   */
  public function run()
  {
    Tag::create(['name' => 'Graphic Design']);
    Tag::create(['name' => 'Programming']);
    Tag::create(['name' => 'Laravel']);
    Tag::create(['name' => 'PHP']);
  }
}

```

C:\xampp82\htdocs\lva7\database\seeders\DatabaseSeeder.php

```php
<?php
namespace Database\Seeders;
// use Illuminate\Database\Console\Seeds\WithoutModelEvents;
use Illuminate\Database\Seeder;
class DatabaseSeeder extends Seeder
{
  /**
   * Seed the application's database.
   */
  public function run(): void
  {
    $this
      ->call(ArticleSeeder::class)
      ->call(CommentSeeder::class)
      ->call(TagSeeder::class)
      ->call(ArticleTagSeeder::class);
  }
}

```

C:\xampp82\htdocs\lva7\app\Livewire\App\Setting.php

```php
<?php
namespace App\Livewire\App;
// use Artesaos\SEOTools\Facades\SEOTools;
use App\Models\User;
use Illuminate\Support\Facades\Hash;
use Illuminate\Validation\Rule;
use Illuminate\Validation\Rules\Password;
use Livewire\Component;
class Setting extends Component
{
  public $user;
  public function mount()
  {
    $userId = auth()->user()->getAuthIdentifier();
    $this->user = User::find($userId)->toArray();
    // SEOTools::setTitle('My setting', false);
  }
  protected function rules()
  {
    return [
      'user.name' => ['required'],
      'user.username' => [
        'required',
        Rule::unique('users', 'username')->ignore(auth()->user()->getAuthIdentifier()),
      ],
      'user.email' => [
        'required',
        Rule::unique('users', 'email')->ignore(auth()->user()->getAuthIdentifier()),
      ],
      'user.password' => ['sometimes', Password::min(8)->letters()->mixedCase()->numbers()->symbols()->uncompromised()],
      'user.image' => ['required'],
      'user.bio' => ['string'],
    ];
  }
  public function render()
  {
    return view('livewire.app.setting');
  }
  public function saveSetting()
  {
    $this->validate();
    $userId = auth()->user()->getAuthIdentifier();
    $user = User::find($userId);
    $user->name = $this->user['name'];
    $user->username = $this->user['username'];
    $user->bio = $this->user['bio'];
    $user->image = $this->user['image'];
    if (array_key_exists('password', $this->user)) {
      $user->password = Hash::make($this->user['password']);
    }
    $user->save();
    $this->user = $user->toArray();
    session()->flash('flash.banner', 'Your settings has been saved');
  }
}

```

C:\xampp82\htdocs\lva7\app\Livewire\App\Register.php

```php
<?php
namespace App\Livewire\App;
// use Artesaos\SEOTools\Facades\SEOTools;
use Illuminate\Support\Facades\Auth;
use Illuminate\Validation\Rules\Password;
use Livewire\Component;
class Register extends Component
{
  public $credentials = [
    'name' => '',
    'username' => '',
    'password' => '',
    'password_confirmation' => '',
  ];
  protected function rules()
  {
    return [
      'credentials.name' => ['required', 'string'],
      'credentials.email' => ['required', 'email', 'unique:users,email'],
      'credentials.username' => ['required', 'email', 'unique:users,username'],
      'credentials.password' => ['required', 'confirmed', Password::min(8)->letters()->mixedCase()->numbers()->symbols()->uncompromised()]
    ];
  }
  public function mount()
  {
    // SEOTools::setTitle('Sign Up', false);
  }
  public function render()
  {
    return view('livewire.app.register');
  }
  public function register()
  {
    $this->validate();
    $user = \App\Models\User::create();
    $user->name = $this->credentials['name'];
    $user->username = $this->credentials['username'];
    $user->password = $this->credentials['password'];
    $user->email = $this->credentials['email'];
    $user->save();
    Auth::loginUsingId($user->id);
    return redirect()->route('front.index');
  }
}

```

C:\xampp82\htdocs\lva7\app\Livewire\App\Login.php

```php
<?php
namespace App\Livewire\App;
// use Artesaos\SEOTools\Facades\SEOTools;
use Illuminate\Support\Facades\Auth;
use Livewire\Component;
class Login extends Component
{
  public $credentials = [
    'email' => '',
    'password' => ''
  ];
  protected $rules = [
    'credentials.email' => ['required', 'email'],
    'credentials.password' => ['required'],
  ];
  public function mount()
  {
    // SEOTools::setTitle('Login', false);
  }
  public function render()
  {
    return view('livewire.app.login');
  }
  public function login()
  {
    $this->validate();
    if (Auth::attempt($this->credentials)) {
      return redirect()->intended(route('front.index'));
    }
    $this->addError('error', 'Wrong email or password');
  }
}

```

C:\xampp82\htdocs\lva7\app\Livewire\App\Article\Edit.php

```php
<?php
namespace App\Livewire\App\Article;
// use Artesaos\SEOTools\Facades\SEOTools;
use App\Models\Article;
use App\Models\Tag;
use Livewire\Component;
use Illuminate\Support\Str;
class Edit extends Component
{
  public Article $article;
  public $tag;
  public $article_tags = [];
  public function mount(Article $article)
  {
    $this->article = $article;
    $this->article_tags = $article->tags->map(function ($tag) {
      return $tag->id;
    });
    // SEOTools::setTitle('Edit article', false);
    // SEOTools::setDescription('Article is being edited.');
  }
  protected $rules = [
    'article.title' => ['required', 'string'],
    'article.body' => ['required', 'string'],
    'article.description' => ['string'],
  ];
  public function render()
  {
    return view('livewire.app.article.edit', [
      'tags' => Tag::all()
    ]);
  }
  public function saveArticle()
  {
    $this->validate();
    $this->article->save();
    $this->article->tags()->sync($this->article_tags);
    session()->flash('flash.banner', 'Your article has been saved!');
    return redirect()->route('app.article.edit', ['article' => $this->article->id]);
  }
  public function deleteArticle()
  {
    $this->article->delete();
    return redirect()->route('front.index');
  }
  public function createTag()
  {
    $slug = Str::slug($this->tag);
    $tag = Tag::where('slug', '=', $slug)->first();
    if ($tag) {
      session()->flash('message-tag', 'Tag has existed.');
      return;
    }
    $this->validate(['tag' => ['required']]);
    if (!empty($this->tag)) {
      Tag::create(['name' => $this->tag]);
      $this->reset('tag');
      session()->flash('message-tag', 'Tag has been created');
    }
  }
}

```

C:\xampp82\htdocs\lva7\app\Livewire\App\Article\Create.php

```php
<?php
namespace App\Livewire\App\Article;
// use Artesaos\SEOTools\Facades\SEOTools;
use App\Models\Article;
use App\Models\Tag;
use Livewire\Component;
use Illuminate\Support\Str;
class Create extends Component
{
  public Article $article;
  public $tag;
  public $article_tags = [];
  public function mount()
  {
    $this->article = new Article();
    // SEOTools::setTitle('Create new article', false);
    // SEOTools::setDescription('New article created here.');
  }
  protected $rules = [
    'article.title' => ['required', 'string'],
    'article.body' => ['required', 'string'],
    'article.description' => ['string'],
  ];
  public function render()
  {
    return view('livewire.app.article.create', [
      'tags' => Tag::all()
    ]);
  }
  public function saveArticle()
  {
    $this->validate();
    $this->article->user_id = auth()->id();
    $this->article->save();
    $this->article->tags()->sync($this->article_tags);
    session()->flash('flash.banner', 'Your article has been published!');
    return redirect()->route('app.article.edit', ['article' => $this->article->id]);
  }
  public function createTag()
  {
    $slug = Str::slug($this->tag);
    $tag = Tag::where('slug', '=', $slug)->first();
    if ($tag) {
      session()->flash('message-tag', 'Tag has existed.');
      return;
    }
    $this->validate(['tag' => ['required']]);
    if (!empty($this->tag)) {
      Tag::create(['name' => $this->tag]);
      $this->reset('tag');
      session()->flash('message-tag', 'Tag has been created');
    }
  }
}

```

C:\xampp82\htdocs\lva7\app\Livewire\Front\Article\Show\.php

```php
<?php
namespace App\Livewire\Front\Article;
// use Artesaos\SEOTools\Facades\SEOTools;
use App\Models\Article;
use App\Models\Comment;
use App\Models\User;
use Livewire\Component;
class Show extends Component
{
  public $article;
  public $user;
  public $comment = '';
  protected $rules = [
    'comment' => ['required', 'string']
  ];
  public function mount(Article $article)
  {
    $article->load(['author', 'comments']);
    $this->article = $article;
    if (auth()->check()) {
      $this->user = User::find(auth()->id());
    }
    // SEOTools::setTitle("{$article->title} | Conduit X Ricardo Sawir", false);
    // SEOTools::setDescription($article->description);
  }
  public function render()
  {
    return view('livewire.front.article.show');
  }
  public function saveComment()
  {
    $this->validate();
    $commenter = User::find(auth()->id());
    $comment = new Comment();
    $comment->article_id = $this->article->id;
    $comment->user_id = $commenter->id;
    $comment->body = $this->comment;
    $comment->save();
    $this->article = Article::find($this->article->id);
    $this->comment = '';
  }
  public function deleteComment($id)
  {
    $comment = Comment::findOrFail($id);
    $comment->delete();
    $this->article = Article::find($this->article->id);
    session()->flash('flash.banner', 'Successfully deleted your comment.');
  }
  public function followAuthor()
  {
    $user = User::find(auth()->id());
    $user->toggleFollow($this->article->author);
    $this->article = Article::find($this->article->id);
  }
  public function favoriteArticle()
  {
    $user = User::find(auth()->id());
    $user->toggleFavorite($this->article);
    $this->article = Article::find($this->article->id);
  }
}

```

C:\xampp82\htdocs\lva7\app\Livewire\Front\Tag\Show\.php

```php
<?php
namespace App\Livewire\Front\Tag;
// use Artesaos\SEOTools\Facades\SEOTools;
use App\Models\Tag;
use Livewire\Component;
class Show extends Component
{
  public Tag $tag;
  public function mount(Tag $tag)
  {
    $tag->load(['articles']);
    $this->tag = $tag;
    // SEOTools::setTitle("{$tag->name} | Conduit X Ricardo Sawir", false);
    // SEOTools::setDescription($tag->name);
  }
  public function render()
  {
    return view('livewire.front.tag.show', [
      'tags' => Tag::all()
    ]);
  }
}

```

C:\xampp82\htdocs\lva7\app\Livewire\Front\User\Show\.php

```php
<?php
namespace App\Livewire\Front\User;
// use Artesaos\SEOTools\Facades\SEOTools;
use App\Models\Article;
use App\Models\User;
use Livewire\Component;
class Show extends Component
{
  public $user;
  public $articles;
  public $loggedInUser;
  public $viewingFavoriteArticles = false;
  public function updatedViewingFavoriteArticles()
  {
    if ($this->viewingFavoriteArticles) {
      $this->articles = $this->user->favorites(Article::class)->with(['author'])->get();
    }
    if (!$this->viewingFavoriteArticles) {
      $this->articles = Article::where('user_id', '=', $this->user->id)->with(['author'])->get();
    }
  }
  public function mount(User $user)
  {
    $this->articles = Article::where('user_id', '=', $this->user->id)->with(['author'])->get();
    $this->user = $user;
    $this->loggedInUser = User::find(auth()->id());
    // SEOTools::setTitle($this->user['name'], false);
    // SEOTools::setDescription($this->user['bio']);
  }
  public function render()
  {
    return view('livewire.front.user.show');
  }
  public function followUser()
  {
    $this->loggedInUser = User::find(auth()->id());
    $this->loggedInUser->toggleFollow($this->user);
    $this->user = User::find($this->user->id);
  }
}

```

C:\xampp82\htdocs\lva7\app\Models\Article.php

```php
<?php
namespace App\Models;
// use Cviebrock\EloquentSluggable\Sluggable;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
// use Multicaret\Acquaintances\Traits\CanBeFavorited;
class Article extends Model
{
  use HasFactory;
  // use Sluggable;
  // use CanBeFavorited;
  public function sluggable(): array
  {
    return [
      'slug' => [
        'source' => 'title'
      ]
    ];
  }
  public function comments()
  {
    return $this->hasMany(Comment::class);
  }
  public function tags()
  {
    return $this->belongsToMany(Tag::class);
  }
  public function author()
  {
    return $this->belongsTo(User::class, 'user_id');
  }
}

```

C:\xampp82\htdocs\lva7\app\Models\Comment.php

```php
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Comment extends Model
{
  use HasFactory;
  public function author()
  {
    return $this->belongsTo(User::class, 'user_id');
  }
  public function article()
  {
    return $this->belongsTo(Article::class);
  }
}

```

C:\xampp82\htdocs\lva7\app\Models\Tag.php

```php
<?php
namespace App\Models;
// use Cviebrock\EloquentSluggable\Sluggable;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Tag extends Model
{
  use HasFactory;
  // use Sluggable;
  protected $fillable = ['name'];
  public function sluggable(): array
  {
    return [
      'slug' => [
        'source' => 'name'
      ]
    ];
  }
  public function articles()
  {
    return $this->belongsToMany(Article::class);
  }
}

```

C:\xampp82\htdocs\lva7\app\Models\User.php

```php
<?php
namespace App\Models;
// use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Laravel\Sanctum\HasApiTokens;
class User extends Authenticatable
{
  use HasApiTokens, HasFactory, Notifiable;
  /**
   * The attributes that are mass assignable.
   *
   * @var array<int, string>
   */
  protected $fillable = [
    'name',
    'email',
    'password',
  ];
  /**
   * The attributes that should be hidden for serialization.
   *
   * @var array<int, string>
   */
  protected $hidden = [
    'password',
    'remember_token',
  ];
  /**
   * The attributes that should be cast.
   *
   * @var array<string, string>
   */
  protected $casts = [
    'email_verified_at' => 'datetime',
  ];
  public function articles()
  {
    return $this->hasMany(Article::class);
  }
  public function comments()
  {
    return $this->hasMany(Comment::class);
  }
}

```

C:\xampp82\htdocs\lva7\app\Providers\AppServiceProvider.php

```php
<?php
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
use Spatie\Menu\Html;
use Spatie\Menu\Laravel\Menu;
use Spatie\Menu\Link;
class AppServiceProvider extends ServiceProvider
{
  /**
   * Register any application services.
   */
  public function register(): void
  {
    //
  }
  /**
   * Bootstrap any application services.
   */
  public function boot(): void
  {
    $this->bootMenu();
  }
  public function bootMenu()
  {
    Menu::macro('app', function () {
      return Menu::new()
        ->addClass('nav navbar-nav pull-xs-right')
        ->add(Link::to(route('front.index'), 'Home'))
        ->addIf(
          auth()->check(),
          Link::to(
            route('app.article.create'),
            Html::raw('<i class="ion-compose"></i>&nbsp;New Post')->render()
          )
        )
        ->addIf(
          auth()->check(),
          Link::to(
            route('app.setting'),
            Html::raw('<i class="ion-gear-a"></i>&nbsp;Settings')->render()
          )
        )
        ->addIf(
          auth()->check(),
          Html::raw('<form id="logout" method="POST" action="' . route('logout') . '"><a href="#" class="nav-link" onclick="event.preventDefault();this.closest(`form`).submit()">Logout</a>' . csrf_field() . '</form>')->addParentClass('nav-item')
        )
        ->addIf(
          !auth()->check(),
          Link::to(route('app.login'), 'Sign In')
        )
        ->addIf(
          !auth()->check(),
          Link::to(route('app.register'), 'Sign Up')
        )
        ->each(function (Link $link) {
          return $link->addParentClass('nav-item');
        })
        ->each(function (Link $link) {
          return $link->addClass('nav-link');
        })
        ->setActiveClassOnLink('active')
        ->setActiveFromRequest();
    });
  }
}

```

###

{% file src="<https://1957079826-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MCBeDUD-PK_RF-YgJRe%2Fuploads%2FNwgym5AYmp3wbKMVt4Bf%2Flva7.zip?alt=media&token=694e2a87-eff2-405b-a108-803a16fea7d8>" %}

### Ví dụ 3: Ta đi nghiên cứu cách dùng phần   kết hợp với menu

Đã có 1 bài viết sử dụng <https://c-i-ph-n-m-m-tr-n-ubuntu-c-n-thi.gitbook.io/learn-lavarel/use-package-lavary-laravel-menu-create-menu-have-role-and-permission-ok> rất dễ dàng rồi nhưng đó  là với gói&#x20;

```json
lavary/laravel-menu
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://learnphp.gitbook.io/learnphp/learn-lavarel/package-spatie-menu-full-phan-1-ok.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
