Add Language Management Module: Created Language resource with CRUD pages, schemas, and models to support the universal translation system. Implemented localization for English and Turkish, ensuring consistent user experience. Added necessary policies and seeder for initial language data, enhancing the overall language management functionality.
This commit is contained in:
+13
-1
@@ -2,13 +2,14 @@
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use App\Traits\HasTranslations;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
|
||||
class Blog extends Model
|
||||
{
|
||||
use HasFactory, SoftDeletes;
|
||||
use HasFactory, SoftDeletes, HasTranslations;
|
||||
|
||||
protected $fillable = [
|
||||
'title',
|
||||
@@ -28,6 +29,17 @@ class Blog extends Model
|
||||
'allow_comments',
|
||||
];
|
||||
|
||||
/**
|
||||
* Translatable fields
|
||||
*/
|
||||
protected $translatable = [
|
||||
'title',
|
||||
'content',
|
||||
'excerpt',
|
||||
'meta_title',
|
||||
'meta_description',
|
||||
];
|
||||
|
||||
protected $casts = [
|
||||
'published_at' => 'datetime',
|
||||
'tags' => 'array',
|
||||
|
||||
@@ -0,0 +1,124 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||
|
||||
class Language extends Model
|
||||
{
|
||||
use HasFactory, SoftDeletes;
|
||||
|
||||
protected $fillable = [
|
||||
'code',
|
||||
'name',
|
||||
'native_name',
|
||||
'flag',
|
||||
'direction',
|
||||
'is_active',
|
||||
'is_default',
|
||||
'sort_order',
|
||||
'created_by',
|
||||
'updated_by',
|
||||
];
|
||||
|
||||
protected $casts = [
|
||||
'is_active' => 'boolean',
|
||||
'is_default' => 'boolean',
|
||||
'sort_order' => 'integer',
|
||||
];
|
||||
|
||||
/**
|
||||
* Boot method
|
||||
*/
|
||||
protected static function boot(): void
|
||||
{
|
||||
parent::boot();
|
||||
|
||||
// Only one default language allowed
|
||||
static::saving(function ($language) {
|
||||
if ($language->is_default) {
|
||||
static::where('id', '!=', $language->id)->update(['is_default' => false]);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Relationships
|
||||
*/
|
||||
public function translations(): HasMany
|
||||
{
|
||||
return $this->hasMany(Translation::class, 'language_code', 'code');
|
||||
}
|
||||
|
||||
public function userLanguages(): HasMany
|
||||
{
|
||||
return $this->hasMany(UserLanguage::class, 'language_code', 'code');
|
||||
}
|
||||
|
||||
public function creator(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(User::class, 'created_by');
|
||||
}
|
||||
|
||||
public function updater(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(User::class, 'updated_by');
|
||||
}
|
||||
|
||||
/**
|
||||
* Scopes
|
||||
*/
|
||||
public function scopeActive($query)
|
||||
{
|
||||
return $query->where('is_active', true);
|
||||
}
|
||||
|
||||
public function scopeOrdered($query)
|
||||
{
|
||||
return $query->orderBy('sort_order')->orderBy('name');
|
||||
}
|
||||
|
||||
/**
|
||||
* Helpers
|
||||
*/
|
||||
public static function getDefault(): ?self
|
||||
{
|
||||
return static::where('is_default', true)->first();
|
||||
}
|
||||
|
||||
public static function getActive(): \Illuminate\Database\Eloquent\Collection
|
||||
{
|
||||
return static::active()->ordered()->get();
|
||||
}
|
||||
|
||||
public static function findByCode(string $code): ?self
|
||||
{
|
||||
return static::where('code', $code)->first();
|
||||
}
|
||||
|
||||
public function activate(): bool
|
||||
{
|
||||
$this->is_active = true;
|
||||
return $this->save();
|
||||
}
|
||||
|
||||
public function deactivate(): bool
|
||||
{
|
||||
if ($this->is_default) {
|
||||
return false; // Cannot deactivate default language
|
||||
}
|
||||
$this->is_active = false;
|
||||
return $this->save();
|
||||
}
|
||||
|
||||
public function setAsDefault(): bool
|
||||
{
|
||||
$this->is_default = true;
|
||||
$this->is_active = true;
|
||||
return $this->save();
|
||||
}
|
||||
}
|
||||
+13
-1
@@ -2,13 +2,14 @@
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use App\Traits\HasTranslations;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
|
||||
class Page extends Model
|
||||
{
|
||||
use HasFactory, SoftDeletes;
|
||||
use HasFactory, SoftDeletes, HasTranslations;
|
||||
|
||||
protected $fillable = [
|
||||
'title',
|
||||
@@ -28,6 +29,17 @@ class Page extends Model
|
||||
'show_in_menu',
|
||||
];
|
||||
|
||||
/**
|
||||
* Translatable fields
|
||||
*/
|
||||
protected $translatable = [
|
||||
'title',
|
||||
'content',
|
||||
'excerpt',
|
||||
'meta_title',
|
||||
'meta_description',
|
||||
];
|
||||
|
||||
protected $casts = [
|
||||
'published_at' => 'datetime',
|
||||
'is_homepage' => 'boolean',
|
||||
|
||||
@@ -0,0 +1,201 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
use Illuminate\Database\Eloquent\Relations\MorphTo;
|
||||
|
||||
class Translation extends Model
|
||||
{
|
||||
use HasFactory, SoftDeletes;
|
||||
|
||||
protected $fillable = [
|
||||
'translatable_type',
|
||||
'translatable_id',
|
||||
'language_code',
|
||||
'field_name',
|
||||
'field_value',
|
||||
'status',
|
||||
'version',
|
||||
'created_by',
|
||||
'updated_by',
|
||||
'approved_by',
|
||||
'approved_at',
|
||||
'published_at',
|
||||
];
|
||||
|
||||
protected $casts = [
|
||||
'version' => 'integer',
|
||||
'approved_at' => 'datetime',
|
||||
'published_at' => 'datetime',
|
||||
];
|
||||
|
||||
/**
|
||||
* Relationships
|
||||
*/
|
||||
public function translatable(): MorphTo
|
||||
{
|
||||
return $this->morphTo();
|
||||
}
|
||||
|
||||
public function language(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(Language::class, 'language_code', 'code');
|
||||
}
|
||||
|
||||
public function creator(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(User::class, 'created_by');
|
||||
}
|
||||
|
||||
public function updater(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(User::class, 'updated_by');
|
||||
}
|
||||
|
||||
public function approver(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(User::class, 'approved_by');
|
||||
}
|
||||
|
||||
/**
|
||||
* Scopes
|
||||
*/
|
||||
public function scopeForModel($query, string $modelClass, int $modelId)
|
||||
{
|
||||
return $query->where('translatable_type', $modelClass)
|
||||
->where('translatable_id', $modelId);
|
||||
}
|
||||
|
||||
public function scopeForLanguage($query, string $languageCode)
|
||||
{
|
||||
return $query->where('language_code', $languageCode);
|
||||
}
|
||||
|
||||
public function scopeForField($query, string $fieldName)
|
||||
{
|
||||
return $query->where('field_name', $fieldName);
|
||||
}
|
||||
|
||||
public function scopePublished($query)
|
||||
{
|
||||
return $query->where('status', 'published');
|
||||
}
|
||||
|
||||
public function scopeApproved($query)
|
||||
{
|
||||
return $query->whereIn('status', ['approved', 'published']);
|
||||
}
|
||||
|
||||
public function scopeDraft($query)
|
||||
{
|
||||
return $query->where('status', 'draft');
|
||||
}
|
||||
|
||||
public function scopeReview($query)
|
||||
{
|
||||
return $query->where('status', 'review');
|
||||
}
|
||||
|
||||
public function scopePendingApproval($query)
|
||||
{
|
||||
return $query->whereIn('status', ['draft', 'review']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Workflow Methods
|
||||
*/
|
||||
public function submitForReview(): bool
|
||||
{
|
||||
if ($this->status === 'draft') {
|
||||
$this->status = 'review';
|
||||
return $this->save();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public function approve(?int $userId = null): bool
|
||||
{
|
||||
if (in_array($this->status, ['draft', 'review'])) {
|
||||
$this->status = 'approved';
|
||||
$this->approved_by = $userId ?? auth()->id();
|
||||
$this->approved_at = now();
|
||||
return $this->save();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public function publish(?int $userId = null): bool
|
||||
{
|
||||
if (in_array($this->status, ['approved', 'draft', 'review'])) {
|
||||
$this->status = 'published';
|
||||
$this->published_at = now();
|
||||
if (!$this->approved_by) {
|
||||
$this->approved_by = $userId ?? auth()->id();
|
||||
$this->approved_at = now();
|
||||
}
|
||||
return $this->save();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public function reject(): bool
|
||||
{
|
||||
if ($this->status === 'review') {
|
||||
$this->status = 'draft';
|
||||
return $this->save();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public function unpublish(): bool
|
||||
{
|
||||
if ($this->status === 'published') {
|
||||
$this->status = 'approved';
|
||||
$this->published_at = null;
|
||||
return $this->save();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper Methods
|
||||
*/
|
||||
public function isDraft(): bool
|
||||
{
|
||||
return $this->status === 'draft';
|
||||
}
|
||||
|
||||
public function isReview(): bool
|
||||
{
|
||||
return $this->status === 'review';
|
||||
}
|
||||
|
||||
public function isApproved(): bool
|
||||
{
|
||||
return $this->status === 'approved';
|
||||
}
|
||||
|
||||
public function isPublished(): bool
|
||||
{
|
||||
return $this->status === 'published';
|
||||
}
|
||||
|
||||
public function canBeEdited(): bool
|
||||
{
|
||||
return in_array($this->status, ['draft', 'review']);
|
||||
}
|
||||
|
||||
public function canBeApproved(): bool
|
||||
{
|
||||
return in_array($this->status, ['draft', 'review']);
|
||||
}
|
||||
|
||||
public function canBePublished(): bool
|
||||
{
|
||||
return in_array($this->status, ['draft', 'review', 'approved']);
|
||||
}
|
||||
}
|
||||
@@ -4,6 +4,7 @@ namespace App\Models;
|
||||
|
||||
// use Illuminate\Contracts\Auth\MustVerifyEmail;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||
use Illuminate\Foundation\Auth\User as Authenticatable;
|
||||
use Illuminate\Notifications\Notifiable;
|
||||
use Spatie\Permission\Traits\HasRoles;
|
||||
@@ -46,4 +47,128 @@ class User extends Authenticatable
|
||||
'password' => 'hashed',
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Relationships
|
||||
*/
|
||||
public function userLanguages(): HasMany
|
||||
{
|
||||
return $this->hasMany(UserLanguage::class);
|
||||
}
|
||||
|
||||
public function languages()
|
||||
{
|
||||
return $this->belongsToMany(Language::class, 'user_languages', 'user_id', 'language_code', 'id', 'code')
|
||||
->withPivot(['can_create', 'can_edit', 'can_approve', 'can_publish'])
|
||||
->withTimestamps();
|
||||
}
|
||||
|
||||
/**
|
||||
* Language Management Methods
|
||||
*/
|
||||
public function canManageLanguage(string $languageCode): bool
|
||||
{
|
||||
// Super admin can manage all languages
|
||||
if ($this->hasRole('super_admin')) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return $this->userLanguages()
|
||||
->where('language_code', $languageCode)
|
||||
->where(function ($query) {
|
||||
$query->where('can_create', true)
|
||||
->orWhere('can_edit', true)
|
||||
->orWhere('can_approve', true)
|
||||
->orWhere('can_publish', true);
|
||||
})
|
||||
->exists();
|
||||
}
|
||||
|
||||
public function canCreateInLanguage(string $languageCode): bool
|
||||
{
|
||||
if ($this->hasRole('super_admin')) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return $this->userLanguages()
|
||||
->where('language_code', $languageCode)
|
||||
->where('can_create', true)
|
||||
->exists();
|
||||
}
|
||||
|
||||
public function canEditInLanguage(string $languageCode): bool
|
||||
{
|
||||
if ($this->hasRole('super_admin')) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return $this->userLanguages()
|
||||
->where('language_code', $languageCode)
|
||||
->where('can_edit', true)
|
||||
->exists();
|
||||
}
|
||||
|
||||
public function canApproveInLanguage(string $languageCode): bool
|
||||
{
|
||||
if ($this->hasRole('super_admin')) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return $this->userLanguages()
|
||||
->where('language_code', $languageCode)
|
||||
->where('can_approve', true)
|
||||
->exists();
|
||||
}
|
||||
|
||||
public function canPublishInLanguage(string $languageCode): bool
|
||||
{
|
||||
if ($this->hasRole('super_admin')) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return $this->userLanguages()
|
||||
->where('language_code', $languageCode)
|
||||
->where('can_publish', true)
|
||||
->exists();
|
||||
}
|
||||
|
||||
public function getManagedLanguages(): \Illuminate\Support\Collection
|
||||
{
|
||||
return $this->userLanguages()
|
||||
->with('language')
|
||||
->get()
|
||||
->pluck('language');
|
||||
}
|
||||
|
||||
public function getManagedLanguageCodes(): array
|
||||
{
|
||||
return $this->userLanguages()
|
||||
->pluck('language_code')
|
||||
->toArray();
|
||||
}
|
||||
|
||||
public function assignLanguage(
|
||||
string $languageCode,
|
||||
bool $canCreate = true,
|
||||
bool $canEdit = true,
|
||||
bool $canApprove = false,
|
||||
bool $canPublish = false
|
||||
): UserLanguage {
|
||||
return $this->userLanguages()->updateOrCreate(
|
||||
['language_code' => $languageCode],
|
||||
[
|
||||
'can_create' => $canCreate,
|
||||
'can_edit' => $canEdit,
|
||||
'can_approve' => $canApprove,
|
||||
'can_publish' => $canPublish,
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
public function removeLanguage(string $languageCode): bool
|
||||
{
|
||||
return $this->userLanguages()
|
||||
->where('language_code', $languageCode)
|
||||
->delete() > 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,105 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
|
||||
class UserLanguage extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
|
||||
protected $fillable = [
|
||||
'user_id',
|
||||
'language_code',
|
||||
'can_create',
|
||||
'can_edit',
|
||||
'can_approve',
|
||||
'can_publish',
|
||||
];
|
||||
|
||||
protected $casts = [
|
||||
'can_create' => 'boolean',
|
||||
'can_edit' => 'boolean',
|
||||
'can_approve' => 'boolean',
|
||||
'can_publish' => 'boolean',
|
||||
];
|
||||
|
||||
/**
|
||||
* Relationships
|
||||
*/
|
||||
public function user(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(User::class);
|
||||
}
|
||||
|
||||
public function language(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(Language::class, 'language_code', 'code');
|
||||
}
|
||||
|
||||
/**
|
||||
* Scopes
|
||||
*/
|
||||
public function scopeForUser($query, int $userId)
|
||||
{
|
||||
return $query->where('user_id', $userId);
|
||||
}
|
||||
|
||||
public function scopeForLanguage($query, string $languageCode)
|
||||
{
|
||||
return $query->where('language_code', $languageCode);
|
||||
}
|
||||
|
||||
public function scopeCanCreate($query)
|
||||
{
|
||||
return $query->where('can_create', true);
|
||||
}
|
||||
|
||||
public function scopeCanEdit($query)
|
||||
{
|
||||
return $query->where('can_edit', true);
|
||||
}
|
||||
|
||||
public function scopeCanApprove($query)
|
||||
{
|
||||
return $query->where('can_approve', true);
|
||||
}
|
||||
|
||||
public function scopeCanPublish($query)
|
||||
{
|
||||
return $query->where('can_publish', true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper Methods
|
||||
*/
|
||||
public function hasFullAccess(): bool
|
||||
{
|
||||
return $this->can_create && $this->can_edit && $this->can_approve && $this->can_publish;
|
||||
}
|
||||
|
||||
public function hasNoAccess(): bool
|
||||
{
|
||||
return !$this->can_create && !$this->can_edit && !$this->can_approve && !$this->can_publish;
|
||||
}
|
||||
|
||||
public function grantFullAccess(): bool
|
||||
{
|
||||
$this->can_create = true;
|
||||
$this->can_edit = true;
|
||||
$this->can_approve = true;
|
||||
$this->can_publish = true;
|
||||
return $this->save();
|
||||
}
|
||||
|
||||
public function revokeAllAccess(): bool
|
||||
{
|
||||
$this->can_create = false;
|
||||
$this->can_edit = false;
|
||||
$this->can_approve = false;
|
||||
$this->can_publish = false;
|
||||
return $this->save();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user