😄Package spatie/menu full phần 1 (ok)
https://spatie.be/docs/menu/v3/introduction
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
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
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
<header>
{!! Menu::main() !!}
</header>
Ví dụ 2: Ta đi nghiên cứu dùng cách xác thực kết hợp với menu
C:\xampp82\htdocs\lva3\database\migrations\2017_12_27_235046_create_roles_table.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
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
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
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
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
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
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
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
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
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
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');
}
}
Ví dụ 2.2: Áp dụng role_user, roles, users
Ví dụ 2.3: Tạo tài khoản và xác thực 😀
C:\xampp82\htdocs\lva7\config\livewire.php
'layout' => 'layouts.app',
C:\xampp82\htdocs\lva7\resources\views\layouts\app.blade.php
<!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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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> New Post')->render()
)
)
->addIf(
auth()->check(),
Link::to(
route('app.setting'),
Html::raw('<i class="ion-gear-a"></i> 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();
});
}
}
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
lavary/laravel-menu
Last updated