1. Create Gallery thumbnail for post select (ok)
Last updated
Last updated
Source code
C:\xampp82\htdocs\lva6\app\Models\Media.php
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Spatie\MediaLibrary\MediaCollections\Models\Media as BaseMedia;
class Media extends BaseMedia
{
use HasFactory;
/**
* The attributes that should be mutated to dates.
*
* @var array
*/
protected $dates = [
'posted_at'
];
}
C:\xampp82\htdocs\lva6\app\Models\MediaLibrary.php
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Spatie\MediaLibrary\HasMedia;
use Spatie\MediaLibrary\InteractsWithMedia;
use Spatie\MediaLibrary\MediaCollections\Models\Media;
class MediaLibrary extends Model implements HasMedia
{
use InteractsWithMedia;
public function registerMediaConversions(Media $media = null): void
{
$this->addMediaConversion('thumb')
->width(350)
->height(250);
}
}
C:\xampp82\htdocs\lva6\app\Models\Post.php
<?php
namespace App\Models;
use App\Scopes\PostedScope;
use DateTimeInterface;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Support\Str;
class Post extends Model
{
use HasFactory;
/**
* The attributes that are mass assignable.
*
* @var array
*/
protected $fillable = [
'author_id',
'title',
'content',
'posted_at',
'slug',
'thumbnail_id',
];
/**
* The attributes that should be mutated to dates.
*
* @var array
*/
protected $dates = [
'posted_at'
];
/**
* The "booting" method of the model.
*/
protected static function boot(): void
{
parent::boot();
static::addGlobalScope(new PostedScope);
}
/**
* Prepare a date for array / JSON serialization.
*/
protected function serializeDate(DateTimeInterface $date): string
{
return $date->format('Y-m-d H:i:s');
}
/**
* Get the route key for the model.
*/
public function getRouteKeyName(): string
{
if (request()->expectsJson()) {
return 'id';
}
return 'slug';
}
/**
* Scope a query to search posts
*/
public function scopeSearch(Builder $query, ?string $search)
{
if ($search) {
return $query->where('title', 'LIKE', "%{$search}%");
}
}
/**
* Scope a query to order posts by latest posted
*/
public function scopeLatest(Builder $query): Builder
{
return $query->orderBy('posted_at', 'desc');
}
/**
* Scope a query to only include posts posted last month.
*/
public function scopeLastMonth(Builder $query, int $limit = 5): Builder
{
return $query->whereBetween('posted_at', [carbon('1 month ago'), now()])
->latest()
->limit($limit);
}
/**
* Scope a query to only include posts posted last week.
*/
public function scopeLastWeek(Builder $query): Builder
{
return $query->whereBetween('posted_at', [carbon('1 week ago'), now()])
->latest();
}
/**
* Return the post's author
*/
public function author(): BelongsTo
{
return $this->belongsTo(User::class, 'author_id');
}
/**
* Return the post's thumbnail
*/
public function thumbnail(): BelongsTo
{
return $this->belongsTo(Media::class);
}
/**
* return the excerpt of the post content
*/
public function excerpt(int $length = 50): string
{
return Str::limit($this->content, $length);
}
/**
* return true if the post has a thumbnail
*/
public function hasThumbnail(): bool
{
return filled($this->thumbnail_id);
}
}
C:\xampp82\htdocs\lva6\app\Models\User.php
<?php
namespace App\Models;
// use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Relations\belongsToMany;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Laravel\Sanctum\HasApiTokens;
use Illuminate\Support\Str;
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',
];
/**
* Get the user's fullname titleized.
*/
public function getFullnameAttribute(): string
{
return Str::title($this->name);
}
/**
* Scope a query to only include users registered last week.
*/
public function scopeLastWeek(Builder $query): Builder
{
return $query->whereBetween('registered_at', [carbon('1 week ago'), now()])
->latest();
}
/**
* Scope a query to order users by latest registered.
*/
public function scopeLatest(Builder $query): Builder
{
return $query->orderBy('registered_at', 'desc');
}
/**
* Check if the user can be an author
*/
public function canBeAuthor(): bool
{
return $this->isAdmin() || $this->isEditor();
}
/**
* Check if the user has role admin
*/
public function isAdmin(): bool
{
// return $this->hasRole(Role::ROLE_ADMIN);
}
/**
* Check if the user has role editor
*/
public function isEditor(): bool
{
// return $this->hasRole(Role::ROLE_EDITOR);
}
/**
* Return the user's posts
*/
public function posts(): HasMany
{
return $this->hasMany(Post::class, 'author_id');
}
/**
* Return the user's comments
*/
public function comments(): HasMany
{
return $this->hasMany(Comment::class, 'author_id');
}
}
C:\xampp82\htdocs\lva6\app\Observers\MediaObserver.php
Hiện tại posted_at chưa hoạt động :( không hiểu tại sao? phải đặt posted_at dưới dạng timestamp giá trị mặc định :(
<?php
namespace App\Observers;
use App\Models\Media;
class MediaObserver
{
/**
* Listen to the Media creating event.
*/
public function creating(Media $medium): void
{
$medium->posted_at = now();
}
}
C:\xampp82\htdocs\lva6\app\Observers\PostObserver.php
<?php
namespace App\Observers;
use App\Models\Post;
use Illuminate\Support\Str;
class PostObserver
{
/**
* Listen to the Post saving event.
*/
public function saving(Post $post): void
{
$post->slug = Str::slug($post->title, '-');
}
}
C:\xampp82\htdocs\lva6\app\Providers\ObserverServiceProvider.php
<?php
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
use App\Models\Media;
use App\Models\Post;
use App\Observers\MediaObserver;
use App\Observers\PostObserver;
class ObserverServiceProvider extends ServiceProvider
{
/**
* Bootstrap the application services.
*/
public function boot(): void
{
Post::observe(PostObserver::class);
Media::observe(MediaObserver::class);
}
}
C:\xampp82\htdocs\lva6\app\Scopes\PostedScope.php
<?php
namespace App\Scopes;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Scope;
use Illuminate\Support\Facades\Auth;
class PostedScope implements Scope
{
/**
* Apply the scope to a given Eloquent query builder.
*/
public function apply(Builder $builder, Model $model): void
{
$user = Auth::user() ?? Auth::guard('api')->user();
// if not connected or if connected but not admin
if (!$user) {
$builder->where('posted_at', '<=', now());
}
}
}
C:\xampp82\htdocs\lva6\app\Providers\RouteServiceProvider.php
<?php
namespace App\Providers;
use Illuminate\Cache\RateLimiting\Limit;
use Illuminate\Foundation\Support\Providers\RouteServiceProvider as ServiceProvider;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\RateLimiter;
use Illuminate\Support\Facades\Route;
class RouteServiceProvider extends ServiceProvider
{
/**
* The path to the "home" route for your application.
*
* Typically, users are redirected here after authentication.
*
* @var string
*/
public const HOME = '/home';
/**
* Define your route model bindings, pattern filters, and other route configuration.
*/
public function boot(): void
{
parent::boot();
$this->configureRateLimiting();
// $this->routes(function () {
// Route::middleware('api')
// ->prefix('api')
// ->group(base_path('routes/api.php'));
// Route::middleware('web')
// ->group(base_path('routes/web.php'));
// });
}
/**
* Define the routes for the application.
*/
public function map(): void
{
$this->mapApiRoutes();
$this->mapAuthRoutes();
$this->mapWebRoutes();
$this->mapAdminRoutes();
}
/**
* Define the "api" routes for the application.
*
* These routes are typically stateless.
*/
protected function mapApiRoutes(): void
{
Route::prefix('api')
->middleware('api')
->group(base_path('routes/api.php'));
}
/**
* Define the "auth" routes for the application.
*
* These routes are typically stateless.
*/
protected function mapAuthRoutes(): void
{
Route::middleware('web')
->group(base_path('routes/auth.php'));
}
/**
* Define the "web" routes for the application.
*
* These routes all receive session state, CSRF protection, etc.
*/
protected function mapWebRoutes(): void
{
Route::middleware('web')
->group(base_path('routes/web.php'));
}
/**
* Define the "admin" routes for the application.
*
* These routes are typically stateless.
*/
protected function mapAdminRoutes(): void
{
Route::prefix('admin')
->middleware(['web', 'auth'])
->as('admin.')
->group(base_path('routes/admin.php'));
}
/**
* Configure the rate limiters for the application.
*/
protected function configureRateLimiting(): void
{
RateLimiter::for('api', function (Request $request) {
return Limit::perMinute(60)->by($request->user()?->id ?: $request->ip());
});
}
}
C:\xampp82\htdocs\lva6\config\app.php
App\Providers\RouteServiceProvider::class,
App\Providers\ObserverServiceProvider::class,
C:\xampp82\htdocs\lva6\database\migrations\2016_12_19_080506_create_posts_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('posts', function (Blueprint $table) {
$table->increments('id');
$table->integer('author_id')->unsigned()->default(0);
$table->string('title')->nullable();
$table->string('slug')->unique();
$table->integer('thumbnail_id')->unsigned()->nullable();
$table->text('content')->nullable();
$table->timestamp('posted_at')->nullable();
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::drop('posts');
}
};
C:\xampp82\htdocs\lva6\database\migrations\2023_10_28_092220_create_media_libraries_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('media_libraries', function (Blueprint $table) {
$table->id();
$table->timestamps();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('media_libraries');
}
};
C:\xampp82\htdocs\lva6\database\migrations\2023_10_30_090733_create_media_table.php
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
public function up(): void
{
Schema::create('media', function (Blueprint $table) {
$table->id();
$table->morphs('model');
$table->uuid('uuid')->nullable()->unique();
$table->string('collection_name');
$table->string('name');
$table->string('file_name');
$table->string('mime_type')->nullable();
$table->string('disk');
$table->string('conversions_disk')->nullable();
$table->unsignedBigInteger('size');
$table->json('manipulations');
$table->json('custom_properties');
$table->json('generated_conversions');
$table->json('responsive_images');
$table->timestamp('posted_at');
$table->unsignedInteger('order_column')->nullable()->index();
$table->nullableTimestamps();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('media');
}
};
C:\xampp82\htdocs\lva6\database\seeders\DatabaseSeeder.php
<?php
namespace Database\Seeders;
// use Illuminate\Database\Console\Seeds\WithoutModelEvents;
use Illuminate\Database\Seeder;
use App\Models\MediaLibrary;
use App\Models\User;
use Illuminate\Support\Facades\Hash;
class DatabaseSeeder extends Seeder
{
/**
* Seed the application's database.
*/
public function run(): void
{
// MediaLibrary
MediaLibrary::firstOrCreate([]);
// Users
$user = User::firstOrCreate(
['email' => 'test1@gmail.com'],
[
'name' => 'test1',
'password' => Hash::make('12345678'),
'email_verified_at' => now()
]
);
}
}
C:\xampp82\htdocs\lva6\routes\web.php
<?php
use App\Http\Controllers\PostController;
use Illuminate\Support\Facades\Route;
/*
|--------------------------------------------------------------------------
| Web Routes
|--------------------------------------------------------------------------
|
| Here is where you can register web routes for your application. These
| routes are loaded by the RouteServiceProvider and all of them will
| be assigned to the "web" middleware group. Make something great!
|
*/
Route::get('/', function () {
return view('welcome');
});
Auth::routes();
Route::get('/home', [App\Http\Controllers\HomeController::class, 'index'])->name('home');
Route::resource('posts', PostController::class)->only('show');