Версия 0.1.0 #1
							
								
								
									
										10
									
								
								app/application/app/Dto/Builder/ProjectLink.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								app/application/app/Dto/Builder/ProjectLink.php
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,10 @@
 | 
				
			|||||||
 | 
					<?php declare(strict_types=1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace App\Dto\Builder;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					final readonly class ProjectLink
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    public function __construct(
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    ) { }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										21
									
								
								app/application/app/Dto/Service/Admin/Project/Link/Index.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								app/application/app/Dto/Service/Admin/Project/Link/Index.php
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,21 @@
 | 
				
			|||||||
 | 
					<?php declare(strict_types=1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace App\Dto\Service\Admin\Project\Link;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use App\Dto\Builder\ProjectLink;
 | 
				
			||||||
 | 
					use App\Dto\Service\Pages;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					final readonly class Index extends Pages
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    public function __construct(
 | 
				
			||||||
 | 
					        private ProjectLink $linkBuilderDto,
 | 
				
			||||||
 | 
					        int $page,
 | 
				
			||||||
 | 
					    ) {
 | 
				
			||||||
 | 
					        parent::__construct($page);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function getLinkBuilderDto(): ProjectLink
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return $this->linkBuilderDto;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -0,0 +1,35 @@
 | 
				
			|||||||
 | 
					<?php declare(strict_types=1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace App\Dto\Service\Admin\Project\Link;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use App\Dto\Service\Dto;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					final readonly class StoreUpdate extends Dto
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    public function __construct(
 | 
				
			||||||
 | 
					        private string $title,
 | 
				
			||||||
 | 
					        private string $link,
 | 
				
			||||||
 | 
					        private int    $sort,
 | 
				
			||||||
 | 
					        private ?int   $languageId,
 | 
				
			||||||
 | 
					    ) { }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function getTitle(): string
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return $this->title;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function getLink(): string
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return $this->link;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function getSort(): int
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return $this->sort;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function getLanguageId(): ?int
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return $this->languageId;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -9,6 +9,7 @@ enum Permission: string
 | 
				
			|||||||
    case User = 'user';
 | 
					    case User = 'user';
 | 
				
			||||||
    case Project = 'project';
 | 
					    case Project = 'project';
 | 
				
			||||||
    case ProjectContent = 'project-content';
 | 
					    case ProjectContent = 'project-content';
 | 
				
			||||||
 | 
					    case ProjectLink = 'project-link';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public function getPermissions(): array
 | 
					    public function getPermissions(): array
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -0,0 +1,100 @@
 | 
				
			|||||||
 | 
					<?php declare(strict_types=1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace App\Http\Controllers\Admin\Projects;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use App\Dto\QuerySettingsDto;
 | 
				
			||||||
 | 
					use App\Http\Controllers\Admin\Controller;
 | 
				
			||||||
 | 
					use App\Http\Requests\Admin\Projects\Links\IndexRequest;
 | 
				
			||||||
 | 
					use App\Http\Requests\Admin\Projects\Links\StoreUpdateRequest;
 | 
				
			||||||
 | 
					use App\Services\Admin\Project\LinkService;
 | 
				
			||||||
 | 
					use Illuminate\Http\RedirectResponse;
 | 
				
			||||||
 | 
					use Illuminate\Http\Request;
 | 
				
			||||||
 | 
					use Illuminate\View\View;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					final class LinksController extends Controller
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    public function __construct(
 | 
				
			||||||
 | 
					        private readonly LinkService $linkService
 | 
				
			||||||
 | 
					    ) { }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function index(int $projectId, IndexRequest $request): View
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $user = $request->user();
 | 
				
			||||||
 | 
					        $data = $request->getDto();
 | 
				
			||||||
 | 
					        $querySettingsDto = new QuerySettingsDto(
 | 
				
			||||||
 | 
					            limit: 20,
 | 
				
			||||||
 | 
					            page: $data->getPage(),
 | 
				
			||||||
 | 
					            queryWith: ['language']
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $result = $this->linkService->index($projectId, $data->getLinkBuilderDto(), $querySettingsDto, $user);
 | 
				
			||||||
 | 
					        if ($result->isError()) {
 | 
				
			||||||
 | 
					            $this->errors($result);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return view('admin/projects/links/index', $result->getData());
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function create(int $projectId, Request $request): View
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $user = $request->user();
 | 
				
			||||||
 | 
					        $result = $this->linkService->create($projectId, $user);
 | 
				
			||||||
 | 
					        if ($result->isError()) {
 | 
				
			||||||
 | 
					            $this->errors($result);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return view('admin/projects/links/create', $result->getData());
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function edit(int $projectId, int $id, Request $request): View
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $user = $request->user();
 | 
				
			||||||
 | 
					        $result = $this->linkService->edit($projectId, $id, $user);
 | 
				
			||||||
 | 
					        if ($result->isError()) {
 | 
				
			||||||
 | 
					            $this->errors($result);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return view('admin/projects/links/edit', $result->getData());
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function store(int $projectId, StoreUpdateRequest $request): RedirectResponse
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $data = $request->getDto();
 | 
				
			||||||
 | 
					        $user = $request->user();
 | 
				
			||||||
 | 
					        $result = $this->linkService->store($projectId, $data, $user);
 | 
				
			||||||
 | 
					        if ($result->isError()) {
 | 
				
			||||||
 | 
					            return redirect()->back()->withInput()->withErrors($result->getErrorsOrMessage());
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return redirect()->route('admin.projects.links.edit', [
 | 
				
			||||||
 | 
					            'project' => $projectId,
 | 
				
			||||||
 | 
					            'link'    => $result->getModel()->id,
 | 
				
			||||||
 | 
					        ])->withSuccess($result->getMessage());
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function update(int $projectId, int $id, StoreUpdateRequest $request): RedirectResponse
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $data = $request->getDto();
 | 
				
			||||||
 | 
					        $user = $request->user();
 | 
				
			||||||
 | 
					        $result = $this->linkService->update($projectId, $id, $data, $user);
 | 
				
			||||||
 | 
					        if ($result->isError()) {
 | 
				
			||||||
 | 
					            return redirect()->back()->withInput()->withErrors($result->getErrorsOrMessage());
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return redirect()->route('admin.projects.links.edit', [
 | 
				
			||||||
 | 
					            'project' => $projectId,
 | 
				
			||||||
 | 
					            'link'    => $result->getModel()->id,
 | 
				
			||||||
 | 
					        ])->withSuccess($result->getMessage());
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function destroy(int $projectId, int $id, Request $request): RedirectResponse
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $user = $request->user();
 | 
				
			||||||
 | 
					        $result = $this->linkService->destroy($projectId, $id, $user);
 | 
				
			||||||
 | 
					        if ($result->isError()) {
 | 
				
			||||||
 | 
					            return redirect()->back()->withInput()->withErrors($result->getErrorsOrMessage());
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return redirect()->route('admin.projects.links.index', ['project' => $projectId])->withSuccess($result->getMessage());
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -0,0 +1,29 @@
 | 
				
			|||||||
 | 
					<?php declare(strict_types=1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace App\Http\Requests\Admin\Projects\Links;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use App\Contracts\FormRequestDto;
 | 
				
			||||||
 | 
					use App\Dto\Builder\ProjectLink;
 | 
				
			||||||
 | 
					use App\Dto\Service\Admin\Project\Link\Index;
 | 
				
			||||||
 | 
					use Illuminate\Foundation\Http\FormRequest;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					final class IndexRequest extends FormRequest implements FormRequestDto
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Get the validation rules that apply to the request.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public function rules(): array
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return [
 | 
				
			||||||
 | 
					            'page' => ['nullable', 'numeric', 'min:1']
 | 
				
			||||||
 | 
					        ];
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function getDto(): Index
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return new Index(
 | 
				
			||||||
 | 
					            linkBuilderDto: new ProjectLink(),
 | 
				
			||||||
 | 
					            page: (int) $this->input('page', 1),
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -0,0 +1,38 @@
 | 
				
			|||||||
 | 
					<?php declare(strict_types=1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace App\Http\Requests\Admin\Projects\Links;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use App\Contracts\FormRequestDto;
 | 
				
			||||||
 | 
					use App\Dto\Service\Admin\Project\Link\StoreUpdate;
 | 
				
			||||||
 | 
					use Illuminate\Foundation\Http\FormRequest;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					final class StoreUpdateRequest extends FormRequest implements FormRequestDto
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Get the validation rules that apply to the request.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public function rules(): array
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return [
 | 
				
			||||||
 | 
					            'title' => ['required', 'string', 'max:255'],
 | 
				
			||||||
 | 
					            'link' => ['required', 'string', 'max:255', 'url:http,https'],
 | 
				
			||||||
 | 
					            'sort' => ['required', 'integer', 'min:-1000', 'max:1000'],
 | 
				
			||||||
 | 
					            'language_id' => ['nullable', 'integer', 'min:1'],
 | 
				
			||||||
 | 
					        ];
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function getDto(): StoreUpdate
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $languageId = $this->input('language_id');
 | 
				
			||||||
 | 
					        if (! \is_null($languageId)) {
 | 
				
			||||||
 | 
					            $languageId = (int) $languageId;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return new StoreUpdate(
 | 
				
			||||||
 | 
					            title: $this->input('title'),
 | 
				
			||||||
 | 
					            link: $this->input('link'),
 | 
				
			||||||
 | 
					            sort: (int) $this->input('sort'),
 | 
				
			||||||
 | 
					            languageId: $languageId,
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -52,4 +52,9 @@ final class Project extends Model implements StorageContract
 | 
				
			|||||||
    {
 | 
					    {
 | 
				
			||||||
        return $this->hasMany(ProjectContent::class);
 | 
					        return $this->hasMany(ProjectContent::class);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function links(): HasMany
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return $this->hasMany(ProjectLink::class);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										46
									
								
								app/application/app/Models/ProjectLink.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										46
									
								
								app/application/app/Models/ProjectLink.php
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,46 @@
 | 
				
			|||||||
 | 
					<?php declare(strict_types=1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace App\Models;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use App\Models\Scopes\SortScope;
 | 
				
			||||||
 | 
					use Illuminate\Database\Eloquent\Attributes\ScopedBy;
 | 
				
			||||||
 | 
					use Illuminate\Database\Eloquent\Factories\HasFactory;
 | 
				
			||||||
 | 
					use Illuminate\Database\Eloquent\Model;
 | 
				
			||||||
 | 
					use Illuminate\Database\Eloquent\Relations\BelongsTo;
 | 
				
			||||||
 | 
					use Illuminate\Database\Eloquent\SoftDeletes;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[ScopedBy([SortScope::class])]
 | 
				
			||||||
 | 
					final class ProjectLink extends Model
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    use HasFactory, SoftDeletes;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    protected $table = 'project_links';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Indicates if the model should be timestamped.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @var bool
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public $timestamps = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * The model's default values for attributes.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @var array
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    protected $attributes = [
 | 
				
			||||||
 | 
					        'sort' => 100,
 | 
				
			||||||
 | 
					    ];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    protected $fillable = [
 | 
				
			||||||
 | 
					        'title',
 | 
				
			||||||
 | 
					        'link',
 | 
				
			||||||
 | 
					        'sort',
 | 
				
			||||||
 | 
					        'language_id',
 | 
				
			||||||
 | 
					    ];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function language(): BelongsTo
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return $this->belongsTo(ProjectLanguage::class);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										34
									
								
								app/application/app/Policies/ProjectLinkPolicy.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								app/application/app/Policies/ProjectLinkPolicy.php
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,34 @@
 | 
				
			|||||||
 | 
					<?php declare(strict_types=1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace App\Policies;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use App\Models\ProjectLink;
 | 
				
			||||||
 | 
					use App\Models\User;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					final readonly class ProjectLinkPolicy extends Policy
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    public function viewAny(User $user): bool
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return $user->hasPermission('project-link.view');
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function view(User $user, ProjectLink $link): bool
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return $user->hasPermission('project-link.view');
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function create(User $user): bool
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return $user->hasPermission('project-link.create');
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function update(User $user, ProjectLink $link): bool
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return $user->hasPermission('project-link.update');
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function delete(User $user, ProjectLink $link): bool
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return $user->hasPermission('project-link.delete');
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										32
									
								
								app/application/app/Repositories/ProjectLinkRepository.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								app/application/app/Repositories/ProjectLinkRepository.php
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,32 @@
 | 
				
			|||||||
 | 
					<?php declare(strict_types=1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace App\Repositories;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use App\Contracts\Search;
 | 
				
			||||||
 | 
					use App\Services\ProjectLink\BuilderCommand;
 | 
				
			||||||
 | 
					use App\Services\Search\CreateSearchInstanceCommand;
 | 
				
			||||||
 | 
					use App\Dto\Builder\ProjectLink as ProjectLinkBuilderDto;
 | 
				
			||||||
 | 
					use App\Models\ProjectLink;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					final readonly class ProjectLinkRepository
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    public function __construct(
 | 
				
			||||||
 | 
					        private CreateSearchInstanceCommand $createSearchInstanceCommand,
 | 
				
			||||||
 | 
					        private BuilderCommand $builderCommand
 | 
				
			||||||
 | 
					    ) { }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function getLinksFromProject(int $projectId, ProjectLinkBuilderDto $projectLinkBuilderDto, array $with = []): Search
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $query = $this->builderCommand->execute(
 | 
				
			||||||
 | 
					            query: ProjectLink::query()->where('project_id', $projectId)->with($with),
 | 
				
			||||||
 | 
					            projectLinkBuilderDto: $projectLinkBuilderDto,
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return $this->createSearchInstanceCommand->execute($query);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function getLinkById(int $id): ?ProjectLink
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return ProjectLink::query()->where('id', $id)->first();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										203
									
								
								app/application/app/Services/Admin/Project/LinkService.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										203
									
								
								app/application/app/Services/Admin/Project/LinkService.php
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,203 @@
 | 
				
			|||||||
 | 
					<?php declare(strict_types=1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace App\Services\Admin\Project;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use App\Dto\Builder\ProjectLink as ProjectLinkBuilderDto;
 | 
				
			||||||
 | 
					use App\Dto\QuerySettingsDto;
 | 
				
			||||||
 | 
					use App\Dto\Service\Admin\Project\Link\StoreUpdate;
 | 
				
			||||||
 | 
					use App\Models\ProjectLink;
 | 
				
			||||||
 | 
					use App\Models\User;
 | 
				
			||||||
 | 
					use App\Repositories\ProjectLinkRepository;
 | 
				
			||||||
 | 
					use App\Repositories\ProjectRepository;
 | 
				
			||||||
 | 
					use App\Services\ProjectLink\ProjectLinkCommandHandler;
 | 
				
			||||||
 | 
					use App\Services\Service;
 | 
				
			||||||
 | 
					use Illuminate\Support\Facades\DB;
 | 
				
			||||||
 | 
					use App\ServiceResults\ServiceResultArray;
 | 
				
			||||||
 | 
					use App\ServiceResults\ServiceResultError;
 | 
				
			||||||
 | 
					use App\ServiceResults\ServiceResultSuccess;
 | 
				
			||||||
 | 
					use App\ServiceResults\StoreUpdateResult;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					final class LinkService extends Service
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    public function __construct(
 | 
				
			||||||
 | 
					        private readonly ProjectRepository $projectRepository,
 | 
				
			||||||
 | 
					        private readonly ProjectLinkRepository $projectLinkRepository,
 | 
				
			||||||
 | 
					        private readonly ProjectLinkCommandHandler $projectLinkCommandHandler,
 | 
				
			||||||
 | 
					    ) { }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function index(int $projectId, ProjectLinkBuilderDto $linkBuilderDto, QuerySettingsDto $querySettingsDto, User $user): ServiceResultError | ServiceResultArray
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $project = $this->projectRepository->getProjectById($projectId);
 | 
				
			||||||
 | 
					        if (\is_null($project)) {
 | 
				
			||||||
 | 
					            return $this->errNotFound(__('Not Found'));
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if ($user->cannot('viewAny', ProjectLink::class)) {
 | 
				
			||||||
 | 
					            return $this->errFobidden(__('Access is denied'));
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $links = $this->projectLinkRepository->getLinksFromProject(
 | 
				
			||||||
 | 
					            $project->id,
 | 
				
			||||||
 | 
					            $linkBuilderDto,
 | 
				
			||||||
 | 
					            $querySettingsDto->getQueryWith()
 | 
				
			||||||
 | 
					        )->pagination(
 | 
				
			||||||
 | 
					            $querySettingsDto->getLimit(),
 | 
				
			||||||
 | 
					            $querySettingsDto->getPage()
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return $this->result([
 | 
				
			||||||
 | 
					            'links'   => $links,
 | 
				
			||||||
 | 
					            'project' => $project,
 | 
				
			||||||
 | 
					        ]);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function create(int $projectId, User $user): ServiceResultError | ServiceResultArray
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $project = $this->projectRepository->getProjectById($projectId);
 | 
				
			||||||
 | 
					        if (\is_null($project)) {
 | 
				
			||||||
 | 
					            return $this->errNotFound(__('Not Found'));
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if ($user->cannot('create', ProjectLink::class)) {
 | 
				
			||||||
 | 
					            return $this->errFobidden(__('Access is denied'));
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return $this->result([
 | 
				
			||||||
 | 
					            'link'    => new ProjectLink(),
 | 
				
			||||||
 | 
					            'project' => $project,
 | 
				
			||||||
 | 
					        ]);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function edit(int $projectId, int $linkId, User $user): ServiceResultError | ServiceResultArray
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $project = $this->projectRepository->getProjectById($projectId);
 | 
				
			||||||
 | 
					        if (\is_null($project)) {
 | 
				
			||||||
 | 
					            return $this->errNotFound(__('Not Found'));
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $link = $this->projectLinkRepository->getLinkById($linkId);
 | 
				
			||||||
 | 
					        if (\is_null($link)) {
 | 
				
			||||||
 | 
					            return $this->errNotFound(__('Not Found'));
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if ($user->cannot('view', $link)) {
 | 
				
			||||||
 | 
					            return $this->errFobidden(__('Access is denied'));
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return $this->result([
 | 
				
			||||||
 | 
					            'link'    => $link,
 | 
				
			||||||
 | 
					            'project' => $project,
 | 
				
			||||||
 | 
					        ]);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function store(int $projectId, StoreUpdate $data, User $user): ServiceResultError | StoreUpdateResult
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        if ($user->cannot('create', ProjectLink::class)) {
 | 
				
			||||||
 | 
					            return $this->errFobidden(__('Access is denied'));
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $project = $this->projectRepository->getProjectById($projectId);
 | 
				
			||||||
 | 
					        if (\is_null($project)) {
 | 
				
			||||||
 | 
					            return $this->errNotFound(__('Not Found'));
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (
 | 
				
			||||||
 | 
					            $data->getLanguageId() !== null
 | 
				
			||||||
 | 
					            && $project->languages()->where('id', $data->getLanguageId())->exists() === false
 | 
				
			||||||
 | 
					        ) {
 | 
				
			||||||
 | 
					            return $this->errValidate(
 | 
				
			||||||
 | 
					                __('validation.exists', ['attribute' => __('validation.attributes.language_id')]),
 | 
				
			||||||
 | 
					                ['language_id' => __('validation.exists', ['attribute' => __('validation.attributes.language_id')])]
 | 
				
			||||||
 | 
					            );
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        try {
 | 
				
			||||||
 | 
					            $link = DB::transaction(function () use ($data, $project, $user) {
 | 
				
			||||||
 | 
					                $dataLink = $this->getDataLink($data);
 | 
				
			||||||
 | 
					                return $this->projectLinkCommandHandler->handleStore($project, $dataLink);
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					        } catch (\Throwable $e) {
 | 
				
			||||||
 | 
					            report($e);
 | 
				
			||||||
 | 
					            return $this->errService(__('Server Error'));
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return $this->resultStoreUpdateModel($link, __('The link was successfully created'));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function update(int $projectId, int $linkId, StoreUpdate $data, User $user): ServiceResultError | StoreUpdateResult
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $project = $this->projectRepository->getProjectById($projectId);
 | 
				
			||||||
 | 
					        if (\is_null($project)) {
 | 
				
			||||||
 | 
					            return $this->errNotFound(__('Not Found'));
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (
 | 
				
			||||||
 | 
					            $data->getLanguageId() !== null
 | 
				
			||||||
 | 
					            && $project->languages()->where('id', $data->getLanguageId())->exists() === false
 | 
				
			||||||
 | 
					        ) {
 | 
				
			||||||
 | 
					            return $this->errValidate(
 | 
				
			||||||
 | 
					                __('validation.exists', ['attribute' => __('validation.attributes.language_id')]),
 | 
				
			||||||
 | 
					                ['language_id' => __('validation.exists', ['attribute' => __('validation.attributes.language_id')])]
 | 
				
			||||||
 | 
					            );
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $link = $this->projectLinkRepository->getLinkById($linkId);
 | 
				
			||||||
 | 
					        if (\is_null($link)) {
 | 
				
			||||||
 | 
					            return $this->errNotFound(__('Not Found'));
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if ($user->cannot('update', $link)) {
 | 
				
			||||||
 | 
					            return $this->errFobidden(__('Access is denied'));
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        try {
 | 
				
			||||||
 | 
					            $link = DB::transaction(function () use ($data, $link) {
 | 
				
			||||||
 | 
					                $dataLink = $this->getDataLink($data);
 | 
				
			||||||
 | 
					                return $this->projectLinkCommandHandler->handleUpdate($link, $dataLink);
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					        } catch (\Throwable $e) {
 | 
				
			||||||
 | 
					            report($e);
 | 
				
			||||||
 | 
					            return $this->errService(__('Server Error'));
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return $this->resultStoreUpdateModel($link, __('The link was successfully updated'));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function destroy(int $projectId, int $linkId, User $user): ServiceResultError|ServiceResultSuccess
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $project = $this->projectRepository->getProjectById($projectId);
 | 
				
			||||||
 | 
					        if (\is_null($project)) {
 | 
				
			||||||
 | 
					            return $this->errNotFound(__('Not Found'));
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $link = $this->projectLinkRepository->getLinkById($linkId);
 | 
				
			||||||
 | 
					        if (\is_null($link)) {
 | 
				
			||||||
 | 
					            return $this->errNotFound(__('Not Found'));
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if ($user->cannot('delete', $link)) {
 | 
				
			||||||
 | 
					            return $this->errFobidden(__('Access is denied'));
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        try {
 | 
				
			||||||
 | 
					            DB::transaction(function () use ($link) {
 | 
				
			||||||
 | 
					                $this->projectLinkCommandHandler->handleDestroy($link);
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					        } catch (\Throwable $e) {
 | 
				
			||||||
 | 
					            report($e);
 | 
				
			||||||
 | 
					            return $this->errService(__('Server Error'));
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return $this->ok(__('The link has been deleted'));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private function getDataLink(StoreUpdate $data): array
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return [
 | 
				
			||||||
 | 
					            'title'       => $data->getTitle(),
 | 
				
			||||||
 | 
					            'link'        => $data->getLink(),
 | 
				
			||||||
 | 
					            'sort'        => $data->getSort(),
 | 
				
			||||||
 | 
					            'language_id' => $data->getLanguageId(),
 | 
				
			||||||
 | 
					        ];
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										15
									
								
								app/application/app/Services/ProjectLink/BuilderCommand.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								app/application/app/Services/ProjectLink/BuilderCommand.php
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,15 @@
 | 
				
			|||||||
 | 
					<?php declare(strict_types=1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace App\Services\ProjectLink;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use App\Dto\Builder\ProjectLink as ProjectLinkBuilderDto;
 | 
				
			||||||
 | 
					use Illuminate\Database\Eloquent\Builder;
 | 
				
			||||||
 | 
					use Illuminate\Database\Eloquent\Relations\Relation;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					final readonly class BuilderCommand
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    public function execute(Relation | Builder $query, ProjectLinkBuilderDto $projectLinkBuilderDto): Relation | Builder
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return $query;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -0,0 +1,25 @@
 | 
				
			|||||||
 | 
					<?php declare(strict_types=1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace App\Services\ProjectLink;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use App\Models\Project;
 | 
				
			||||||
 | 
					use App\Models\ProjectLink;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					final readonly class ProjectLinkCommandHandler
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    public function handleStore(Project $project, array $data): ProjectLink
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return $project->links()->create($data);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function handleUpdate(ProjectLink $link, array $data): ProjectLink
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $link->update($data);
 | 
				
			||||||
 | 
					        return $link;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function handleDestroy(ProjectLink $link): void
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $link->delete();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -249,5 +249,9 @@
 | 
				
			|||||||
    "There was an error adding a language": "There was an error adding a language",
 | 
					    "There was an error adding a language": "There was an error adding a language",
 | 
				
			||||||
    "Select images": "Select images",
 | 
					    "Select images": "Select images",
 | 
				
			||||||
    "loading": "loading",
 | 
					    "loading": "loading",
 | 
				
			||||||
    "Project information has been successfully updated": "Project information has been successfully updated"
 | 
					    "Project information has been successfully updated": "Project information has been successfully updated",
 | 
				
			||||||
 | 
					    "in all languages": "in all languages",
 | 
				
			||||||
 | 
					    "The link was successfully created": "The link was successfully created",
 | 
				
			||||||
 | 
					    "The link was successfully updated": "The link was successfully updated",
 | 
				
			||||||
 | 
					    "The link has been deleted": "The link has been deleted",
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -10,4 +10,5 @@ return [
 | 
				
			|||||||
    'About project' => 'About the project',
 | 
					    'About project' => 'About the project',
 | 
				
			||||||
    'Languages' => 'Languages',
 | 
					    'Languages' => 'Languages',
 | 
				
			||||||
    'Last update' => 'Last update',
 | 
					    'Last update' => 'Last update',
 | 
				
			||||||
 | 
					    'Links project' => 'Links from the project',
 | 
				
			||||||
];
 | 
					];
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -3,12 +3,16 @@
 | 
				
			|||||||
return [
 | 
					return [
 | 
				
			||||||
    'Role' => 'User group',
 | 
					    'Role' => 'User group',
 | 
				
			||||||
    'User' => 'Users',
 | 
					    'User' => 'Users',
 | 
				
			||||||
    'Allowed to watch' => 'Allowed to watch',
 | 
					
 | 
				
			||||||
 | 
					    'Allowed to watch'  => 'Allowed to watch',
 | 
				
			||||||
    'Allowed to create' => 'Allowed to create',
 | 
					    'Allowed to create' => 'Allowed to create',
 | 
				
			||||||
    'Allowed to edit' => 'Allowed to edit',
 | 
					    'Allowed to edit'   => 'Allowed to edit',
 | 
				
			||||||
    'Allowed to delete' => 'Allowed to delete',
 | 
					    'Allowed to delete' => 'Allowed to delete',
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    'Administrative panel allowed' => 'Administrative panel allowed',
 | 
					    'Administrative panel allowed' => 'Administrative panel allowed',
 | 
				
			||||||
    'AdminPanel' => 'Administrative panel allowed',
 | 
					    'AdminPanel'                   => 'Administrative panel allowed',
 | 
				
			||||||
    'Project' => 'Projects',
 | 
					
 | 
				
			||||||
 | 
					    'Project'        => 'Projects',
 | 
				
			||||||
    'ProjectContent' => 'About the project',
 | 
					    'ProjectContent' => 'About the project',
 | 
				
			||||||
 | 
					    'ProjectLink'    => 'Links from the project',
 | 
				
			||||||
];
 | 
					];
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -292,5 +292,7 @@ return [
 | 
				
			|||||||
        'logo'                     => 'logo',
 | 
					        'logo'                     => 'logo',
 | 
				
			||||||
        'logo.file'                => 'logo file',
 | 
					        'logo.file'                => 'logo file',
 | 
				
			||||||
        'logo.delete'              => 'remove logo',
 | 
					        'logo.delete'              => 'remove logo',
 | 
				
			||||||
 | 
					        'link'                     => 'link',
 | 
				
			||||||
 | 
					        'language_id'              => 'language',
 | 
				
			||||||
    ],
 | 
					    ],
 | 
				
			||||||
];
 | 
					];
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -249,5 +249,9 @@
 | 
				
			|||||||
    "There was an error adding a language": "Произошла ошибка при добавлении языка",
 | 
					    "There was an error adding a language": "Произошла ошибка при добавлении языка",
 | 
				
			||||||
    "Select images": "Выберите изображения",
 | 
					    "Select images": "Выберите изображения",
 | 
				
			||||||
    "loading": "загрузка",
 | 
					    "loading": "загрузка",
 | 
				
			||||||
    "Project information has been successfully updated": "Информация о проекте успешно обновлена"
 | 
					    "Project information has been successfully updated": "Информация о проекте успешно обновлена",
 | 
				
			||||||
 | 
					    "in all languages": "на всех языках",
 | 
				
			||||||
 | 
					    "The link was successfully created": "Ссылка успешно создана",
 | 
				
			||||||
 | 
					    "The link was successfully updated": "Ссылка успешно обновлена",
 | 
				
			||||||
 | 
					    "The link has been deleted": "Ссылка удалена"
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -10,4 +10,5 @@ return [
 | 
				
			|||||||
    'About project' => 'О проекте',
 | 
					    'About project' => 'О проекте',
 | 
				
			||||||
    'Languages' => 'Языки',
 | 
					    'Languages' => 'Языки',
 | 
				
			||||||
    'Last update' => 'Последнее обновление',
 | 
					    'Last update' => 'Последнее обновление',
 | 
				
			||||||
 | 
					    'Links project' => 'Ссылки от проекта',
 | 
				
			||||||
];
 | 
					];
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -3,13 +3,16 @@
 | 
				
			|||||||
return [
 | 
					return [
 | 
				
			||||||
    'Role' => 'Группа пользователей',
 | 
					    'Role' => 'Группа пользователей',
 | 
				
			||||||
    'User' => 'Пользователи',
 | 
					    'User' => 'Пользователи',
 | 
				
			||||||
    'CaptchaToken' => 'Токены для создания капчи',
 | 
					
 | 
				
			||||||
    'Allowed to watch' => 'Разрешено смотреть',
 | 
					    'Allowed to watch'  => 'Разрешено смотреть',
 | 
				
			||||||
    'Allowed to create' => 'Разрешено создать',
 | 
					    'Allowed to create' => 'Разрешено создать',
 | 
				
			||||||
    'Allowed to edit' => 'Разрешено редактировать',
 | 
					    'Allowed to edit'   => 'Разрешено редактировать',
 | 
				
			||||||
    'Allowed to delete' => 'Разрешено удалять',
 | 
					    'Allowed to delete' => 'Разрешено удалять',
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    'Administrative panel allowed' => 'Административная панель разрешена',
 | 
					    'Administrative panel allowed' => 'Административная панель разрешена',
 | 
				
			||||||
    'AdminPanel' => 'Административная панель разрешена',
 | 
					    'AdminPanel'                   => 'Административная панель разрешена',
 | 
				
			||||||
    'Project' => 'Проекты',
 | 
					
 | 
				
			||||||
 | 
					    'Project'        => 'Проекты',
 | 
				
			||||||
    'ProjectContent' => 'О проекте',
 | 
					    'ProjectContent' => 'О проекте',
 | 
				
			||||||
 | 
					    'ProjectLink'    => 'Ссылки от проекта',
 | 
				
			||||||
];
 | 
					];
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -292,5 +292,7 @@ return [
 | 
				
			|||||||
        'logo'                     => 'логотип',
 | 
					        'logo'                     => 'логотип',
 | 
				
			||||||
        'logo.file'                => 'файл логотипа',
 | 
					        'logo.file'                => 'файл логотипа',
 | 
				
			||||||
        'logo.delete'              => 'удалить логотип',
 | 
					        'logo.delete'              => 'удалить логотип',
 | 
				
			||||||
 | 
					        'link'                     => 'ссылка',
 | 
				
			||||||
 | 
					        'language_id'              => 'язык',
 | 
				
			||||||
    ],
 | 
					    ],
 | 
				
			||||||
];
 | 
					];
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -0,0 +1,11 @@
 | 
				
			|||||||
 | 
					@csrf
 | 
				
			||||||
 | 
					<x-volt.forms.input :title="__('validation.attributes.title')" name="title" type="text" :value="$link->title" required autofocus />
 | 
				
			||||||
 | 
					<x-volt.forms.input :title="__('validation.attributes.link')" name="link" type="text" :value="$link->link" required />
 | 
				
			||||||
 | 
					<x-volt.forms.input :title="__('validation.attributes.sort')" name="sort" type="number" :value="$link->sort" required />
 | 
				
			||||||
 | 
					<x-volt.forms.select :title="__('validation.attributes.language_id')" name="language_id" :list="$project->languages->pluck('title', 'id')->toArray()" :value="(string) $link->language_id">
 | 
				
			||||||
 | 
					    <option value="">{{ __('in all languages') }}</option>
 | 
				
			||||||
 | 
					</x-volt.forms.select>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@canany(['create', 'update'], $link)
 | 
				
			||||||
 | 
					    <button class="btn btn-primary" type="submit">{{ __('Save') }}</button>
 | 
				
			||||||
 | 
					@endcanany
 | 
				
			||||||
@@ -0,0 +1,8 @@
 | 
				
			|||||||
 | 
					@can('create', \App\Models\ProjectLink::class)
 | 
				
			||||||
 | 
					    <div class="mb-4">
 | 
				
			||||||
 | 
					        <a href="{{ route('admin.projects.links.create', ['project' => $project->id]) }}" class="btn btn-secondary d-inline-flex align-items-center me-2">
 | 
				
			||||||
 | 
					            <svg class="icon icon-xs me-2" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 6v6m0 0v6m0-6h6m-6 0H6"></path></svg>
 | 
				
			||||||
 | 
					            {{ __('Create') }}
 | 
				
			||||||
 | 
					        </a>
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					@endcan
 | 
				
			||||||
@@ -0,0 +1,17 @@
 | 
				
			|||||||
 | 
					@section('meta_title', __('admin-sections.Links project'))
 | 
				
			||||||
 | 
					@section('h1', __('admin-sections.Project') . ': ' . $project->name)
 | 
				
			||||||
 | 
					<x-admin.layout>
 | 
				
			||||||
 | 
					    @include('admin.projects.links._top')
 | 
				
			||||||
 | 
					    <div class="row">
 | 
				
			||||||
 | 
					        <div class="col-12 mb-4">
 | 
				
			||||||
 | 
					            <div class="card border-0 shadow components-section">
 | 
				
			||||||
 | 
					                <div class="card-body">
 | 
				
			||||||
 | 
					                    <h3 id="category" class="mb-4">{{ __('admin-sections.Links project') }}</h3>
 | 
				
			||||||
 | 
					                    <form method="post" action="{{ route('admin.projects.links.store', ['project' => $project->id]) }}">
 | 
				
			||||||
 | 
					                        @include('admin.projects.links._from')
 | 
				
			||||||
 | 
					                    </form>
 | 
				
			||||||
 | 
					                </div>
 | 
				
			||||||
 | 
					            </div>
 | 
				
			||||||
 | 
					        </div>
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					</x-admin.layout>
 | 
				
			||||||
@@ -0,0 +1,18 @@
 | 
				
			|||||||
 | 
					@section('meta_title', __('admin-sections.Links project'))
 | 
				
			||||||
 | 
					@section('h1', __('admin-sections.Project') . ': ' . $project->name)
 | 
				
			||||||
 | 
					<x-admin.layout>
 | 
				
			||||||
 | 
					    @include('admin.projects._top')
 | 
				
			||||||
 | 
					    <div class="row">
 | 
				
			||||||
 | 
					        <div class="col-12 mb-4">
 | 
				
			||||||
 | 
					            <div class="card border-0 shadow components-section">
 | 
				
			||||||
 | 
					                <div class="card-body">
 | 
				
			||||||
 | 
					                    <h3 id="category" class="mb-4">{{ __('admin-sections.Links project') }}</h3>
 | 
				
			||||||
 | 
					                    <form method="post" action="{{ route('admin.projects.links.update', ['project' => $project->id, 'link' => $link->id]) }}">
 | 
				
			||||||
 | 
					                        @method('PUT')
 | 
				
			||||||
 | 
					                        @include('admin.projects.links._from')
 | 
				
			||||||
 | 
					                    </form>
 | 
				
			||||||
 | 
					                </div>
 | 
				
			||||||
 | 
					            </div>
 | 
				
			||||||
 | 
					        </div>
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					</x-admin.layout>
 | 
				
			||||||
@@ -0,0 +1,61 @@
 | 
				
			|||||||
 | 
					@section('meta_title', __('admin-sections.Links project'))
 | 
				
			||||||
 | 
					@section('h1', __('admin-sections.Project') . ': ' . $project->name)
 | 
				
			||||||
 | 
					<x-admin.layout>
 | 
				
			||||||
 | 
					    @include('admin.projects.links._top')
 | 
				
			||||||
 | 
					    <div class="card border-0 shadow mb-4">
 | 
				
			||||||
 | 
					        <div class="card-body">
 | 
				
			||||||
 | 
					            <h3 id="category" class="mb-4">{{ __('admin-sections.Links project') }}</h3>
 | 
				
			||||||
 | 
					            <div class="table-responsive">
 | 
				
			||||||
 | 
					                <table class="table table-centered table-nowrap mb-0 rounded">
 | 
				
			||||||
 | 
					                    <thead class="thead-light">
 | 
				
			||||||
 | 
					                    <tr>
 | 
				
			||||||
 | 
					                        <th class="border-0">{{ __('validation.attributes.title') }}</th>
 | 
				
			||||||
 | 
					                        <th class="border-0">{{ __('validation.attributes.link') }}</th>
 | 
				
			||||||
 | 
					                        <th class="border-0">{{ __('validation.attributes.language_id') }}</th>
 | 
				
			||||||
 | 
					                        <th class="border-0 rounded-end" style="width: 150px"></th>
 | 
				
			||||||
 | 
					                    </tr>
 | 
				
			||||||
 | 
					                    </thead>
 | 
				
			||||||
 | 
					                    <tbody>
 | 
				
			||||||
 | 
					                    @foreach($links as $link)
 | 
				
			||||||
 | 
					                        <tr>
 | 
				
			||||||
 | 
					                            <td>
 | 
				
			||||||
 | 
					                                <a href="{{ route('admin.projects.links.edit', ['project' => $project->id, 'link' => $link->id]) }}" class="fw-bold">
 | 
				
			||||||
 | 
					                                    <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="align-text-top" viewBox="0 0 16 16">
 | 
				
			||||||
 | 
					                                        <path d="M12.854.146a.5.5 0 0 0-.707 0L10.5 1.793 14.207 5.5l1.647-1.646a.5.5 0 0 0 0-.708l-3-3zm.646 6.061L9.793 2.5 3.293 9H3.5a.5.5 0 0 1 .5.5v.5h.5a.5.5 0 0 1 .5.5v.5h.5a.5.5 0 0 1 .5.5v.5h.5a.5.5 0 0 1 .5.5v.207l6.5-6.5zm-7.468 7.468A.5.5 0 0 1 6 13.5V13h-.5a.5.5 0 0 1-.5-.5V12h-.5a.5.5 0 0 1-.5-.5V11h-.5a.5.5 0 0 1-.5-.5V10h-.5a.499.499 0 0 1-.175-.032l-.179.178a.5.5 0 0 0-.11.168l-2 5a.5.5 0 0 0 .65.65l5-2a.5.5 0 0 0 .168-.11l.178-.178z"/>
 | 
				
			||||||
 | 
					                                    </svg>
 | 
				
			||||||
 | 
					                                    {{ $link->title }}
 | 
				
			||||||
 | 
					                                </a>
 | 
				
			||||||
 | 
					                            </td>
 | 
				
			||||||
 | 
					                            <td>
 | 
				
			||||||
 | 
					                                {{ $link->link }}
 | 
				
			||||||
 | 
					                            </td>
 | 
				
			||||||
 | 
					                            <td>
 | 
				
			||||||
 | 
					                                {{ $link->language?->title ?? __('in all languages') }}
 | 
				
			||||||
 | 
					                            </td>
 | 
				
			||||||
 | 
					                            <td>
 | 
				
			||||||
 | 
					                                @can('delete', $link)
 | 
				
			||||||
 | 
					                                    <form method="post" class="d-inline-block" action="{{ route('admin.projects.links.destroy', ['project' => $project->id, 'link' => $link->id]) }}">
 | 
				
			||||||
 | 
					                                        @csrf
 | 
				
			||||||
 | 
					                                        @method('DELETE')
 | 
				
			||||||
 | 
					                                        <button type="submit" class="btn btn-danger click-confirm" data-bs-toggle="tooltip" data-bs-placement="top" title="{{ __('Delete') }}">
 | 
				
			||||||
 | 
					                                            <svg data-slot="icon" fill="currentColor" width="20" height="20" class="align-text-center" stroke-width="1.5" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" aria-hidden="true">
 | 
				
			||||||
 | 
					                                                <path stroke-linecap="round" stroke-linejoin="round" d="M6 18 18 6M6 6l12 12"></path>
 | 
				
			||||||
 | 
					                                            </svg>
 | 
				
			||||||
 | 
					                                        </button>
 | 
				
			||||||
 | 
					                                    </form>
 | 
				
			||||||
 | 
					                                @endcan
 | 
				
			||||||
 | 
					                            </td>
 | 
				
			||||||
 | 
					                        </tr>
 | 
				
			||||||
 | 
					                    @endforeach
 | 
				
			||||||
 | 
					                    </tbody>
 | 
				
			||||||
 | 
					                </table>
 | 
				
			||||||
 | 
					                <div class="card-footer border-0">
 | 
				
			||||||
 | 
					                    {{ $links->links() }}
 | 
				
			||||||
 | 
					                </div>
 | 
				
			||||||
 | 
					            </div>
 | 
				
			||||||
 | 
					        </div>
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					    @push('scripts')
 | 
				
			||||||
 | 
					        @include('admin._scripts._click-confirm', ['alert' => __('Do you want to delete?')])
 | 
				
			||||||
 | 
					    @endpush
 | 
				
			||||||
 | 
					</x-admin.layout>
 | 
				
			||||||
@@ -15,7 +15,7 @@
 | 
				
			|||||||
                        @can('viewAny', \App\Models\ProjectContent::class)
 | 
					                        @can('viewAny', \App\Models\ProjectContent::class)
 | 
				
			||||||
                            <tr>
 | 
					                            <tr>
 | 
				
			||||||
                                <td>
 | 
					                                <td>
 | 
				
			||||||
                                    <a href="{{ route('admin.projects.about.languages', ['project' => $project->id])  }}" class="fw-bold">
 | 
					                                    <a href="{{ route('admin.projects.about.languages', ['project' => $project->id]) }}" class="fw-bold">
 | 
				
			||||||
                                        <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="align-text-top" viewBox="0 0 16 16">
 | 
					                                        <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="align-text-top" viewBox="0 0 16 16">
 | 
				
			||||||
                                            <path d="M12.854.146a.5.5 0 0 0-.707 0L10.5 1.793 14.207 5.5l1.647-1.646a.5.5 0 0 0 0-.708l-3-3zm.646 6.061L9.793 2.5 3.293 9H3.5a.5.5 0 0 1 .5.5v.5h.5a.5.5 0 0 1 .5.5v.5h.5a.5.5 0 0 1 .5.5v.5h.5a.5.5 0 0 1 .5.5v.207l6.5-6.5zm-7.468 7.468A.5.5 0 0 1 6 13.5V13h-.5a.5.5 0 0 1-.5-.5V12h-.5a.5.5 0 0 1-.5-.5V11h-.5a.5.5 0 0 1-.5-.5V10h-.5a.499.499 0 0 1-.175-.032l-.179.178a.5.5 0 0 0-.11.168l-2 5a.5.5 0 0 0 .65.65l5-2a.5.5 0 0 0 .168-.11l.178-.178z"/>
 | 
					                                            <path d="M12.854.146a.5.5 0 0 0-.707 0L10.5 1.793 14.207 5.5l1.647-1.646a.5.5 0 0 0 0-.708l-3-3zm.646 6.061L9.793 2.5 3.293 9H3.5a.5.5 0 0 1 .5.5v.5h.5a.5.5 0 0 1 .5.5v.5h.5a.5.5 0 0 1 .5.5v.5h.5a.5.5 0 0 1 .5.5v.207l6.5-6.5zm-7.468 7.468A.5.5 0 0 1 6 13.5V13h-.5a.5.5 0 0 1-.5-.5V12h-.5a.5.5 0 0 1-.5-.5V11h-.5a.5.5 0 0 1-.5-.5V10h-.5a.499.499 0 0 1-.175-.032l-.179.178a.5.5 0 0 0-.11.168l-2 5a.5.5 0 0 0 .65.65l5-2a.5.5 0 0 0 .168-.11l.178-.178z"/>
 | 
				
			||||||
                                        </svg>
 | 
					                                        </svg>
 | 
				
			||||||
@@ -24,6 +24,18 @@
 | 
				
			|||||||
                                </td>
 | 
					                                </td>
 | 
				
			||||||
                            </tr>
 | 
					                            </tr>
 | 
				
			||||||
                        @endcan
 | 
					                        @endcan
 | 
				
			||||||
 | 
					                        @can('viewAny', \App\Models\ProjectLink::class)
 | 
				
			||||||
 | 
					                            <tr>
 | 
				
			||||||
 | 
					                                <td>
 | 
				
			||||||
 | 
					                                    <a href="{{ route('admin.projects.links.index', ['project' => $project->id]) }}" class="fw-bold">
 | 
				
			||||||
 | 
					                                        <svg data-slot="icon" width="16" height="16" fill="none" stroke-width="1.5" stroke="currentColor" class="align-text-top" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" aria-hidden="true">
 | 
				
			||||||
 | 
					                                            <path stroke-linecap="round" stroke-linejoin="round" d="M13.19 8.688a4.5 4.5 0 0 1 1.242 7.244l-4.5 4.5a4.5 4.5 0 0 1-6.364-6.364l1.757-1.757m13.35-.622 1.757-1.757a4.5 4.5 0 0 0-6.364-6.364l-4.5 4.5a4.5 4.5 0 0 0 1.242 7.244"></path>
 | 
				
			||||||
 | 
					                                        </svg>
 | 
				
			||||||
 | 
					                                        {{ __('admin-sections.Links project') }}
 | 
				
			||||||
 | 
					                                    </a>
 | 
				
			||||||
 | 
					                                </td>
 | 
				
			||||||
 | 
					                            </tr>
 | 
				
			||||||
 | 
					                        @endcan
 | 
				
			||||||
                    </tbody>
 | 
					                    </tbody>
 | 
				
			||||||
                </table>
 | 
					                </table>
 | 
				
			||||||
            </div>
 | 
					            </div>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -25,6 +25,8 @@ Route::middleware(['auth', 'verified', \App\Http\Middleware\UserLocale::class])-
 | 
				
			|||||||
            Route::get('about/{language}', [\App\Http\Controllers\Admin\Projects\AboutController::class, 'edit'])->name('about.edit')->where(['language' => '[0-9]+']);
 | 
					            Route::get('about/{language}', [\App\Http\Controllers\Admin\Projects\AboutController::class, 'edit'])->name('about.edit')->where(['language' => '[0-9]+']);
 | 
				
			||||||
            Route::put('about/{language}', [\App\Http\Controllers\Admin\Projects\AboutController::class, 'update'])->name('about.update')->where(['language' => '[0-9]+']);
 | 
					            Route::put('about/{language}', [\App\Http\Controllers\Admin\Projects\AboutController::class, 'update'])->name('about.update')->where(['language' => '[0-9]+']);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            Route::resource('links', \App\Http\Controllers\Admin\Projects\LinksController::class)->except(['show'])->where(['link' => '[0-9]+']);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        })->where(['project' => '[0-9]+']);
 | 
					        })->where(['project' => '[0-9]+']);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        Route::post('languages/new-language', [\App\Http\Controllers\Admin\LanguagesController::class, 'newLanguage'])->name('new-language');
 | 
					        Route::post('languages/new-language', [\App\Http\Controllers\Admin\LanguagesController::class, 'newLanguage'])->name('new-language');
 | 
				
			||||||
@@ -42,4 +44,3 @@ Route::middleware(['auth', 'verified', \App\Http\Middleware\UserLocale::class])-
 | 
				
			|||||||
        Route::post('image/upload-resize', [\App\Http\Controllers\Storage\ImagesController::class, 'uploadAndResize'])->name('image_upload_and_resize');
 | 
					        Route::post('image/upload-resize', [\App\Http\Controllers\Storage\ImagesController::class, 'uploadAndResize'])->name('image_upload_and_resize');
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
});
 | 
					});
 | 
				
			||||||
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user