ldc-dam/app/Http/Controllers/MediaController.php
Jérémy Munsch 0194d8e0c1 Fix Media duplicate
- put in transaction
- set arcadia_id to null
2025-05-06 11:10:13 +02:00

1121 lines
39 KiB
PHP

<?php
namespace App\Http\Controllers;
use App\Enums\MediaExtension;
use App\Enums\MediaStatut;
use App\Events\MediaLinkWithArcadia;
use App\Events\MediaMoved;
use App\Events\MediaSearched;
use App\Http\Requests\Bo\Ajax\ApplyStickerRequest;
use App\Http\Requests\Bo\Ajax\CheckRefKeyRequest;
use App\Http\Requests\Bo\Ajax\DeleteMediaRequest;
use App\Http\Requests\Bo\Ajax\MoveMediaRequest;
use App\Http\Requests\Bo\Ajax\UpdateMediaRequest;
use App\Http\Requests\Bo\DownloadMediaPublicRequest;
use App\Http\Requests\Bo\DownloadMediaRequest;
use App\Http\Requests\Bo\LoadMediaRequest;
use App\Http\Requests\Bo\ShowInterfaceRequest;
use App\Lib\ArcadiaLinkUtilities;
use App\Lib\ToolboxHelper;
use App\Models\Article;
use App\Models\Copyright;
use App\Models\Dossier;
use App\Models\Etiquette;
use App\Models\Format;
use App\Models\Historique;
use App\Models\Langue;
use App\Models\Marque;
use App\Models\Media;
use App\Models\Recherche;
use App\Models\Setting;
use App\Models\Societe;
use App\Models\Sujet;
use App\Models\Tag;
use App\Models\TypeMedia;
use App\Traits\Http\HandlesMedia;
use Illuminate\Contracts\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\ModelNotFoundException;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Arr;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\File;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Str;
use Illuminate\Validation\ValidationException;
use Symfony\Component\HttpFoundation\BinaryFileResponse;
class MediaController extends Controller
{
use HandlesMedia;
/**
* Display a listing of the resource.
*
* @param \App\Http\Requests\Bo\ShowInterfaceRequest $request
* @return \Illuminate\Http\Response
*/
public function showInterface(ShowInterfaceRequest $request)
{
/** @var \App\Models\User */
$user = auth()->user();
$filters = (object)[];
/** @var \Illuminate\Database\Eloquent\Collection<\App\Models\Sujet> */
$sujets = $user->sujets;
// ! Has to flush Media cache before querying basket with media list
Media::flushQueryCache();
/** @var \Illuminate\Database\Eloquent\Collection<\App\Models\Panier> */
$paniers = $user->paniersOwner;
/** @var \Illuminate\Database\Eloquent\Collection<\App\Models\Societe> */
$societes = Societe::orderBy('libelle')->get();
$typesmedia = TypeMedia::all();
$langues = Langue::all();
$copyrights = Copyright::all();
$etiquettes = Etiquette::all();
$marques = Marque::all();
/** @var int|null */
$dossier_id = $request->d;
/** @var \App\Models\Sujet|null */
$sujet = Sujet::where('codeSujet', $request->s)->first();
/** @var string */
$textSearch = \strval($request->t);
/** @var \App\Models\Recherche|null */
$recherche = Recherche::where('id', $request->r)->first();
// * Recherche type texte
if (\strlen($textSearch) and $sujet) {
// * On créé un object filtre.
$filters = (object)[
"search" => [
'type' => "search",
'legend' => "Recherche : ",
'value' => $textSearch,
'libelle' => [$textSearch],
]
];
MediaSearched::dispatch(
$user,
$sujet,
$textSearch,
$filters,
intval(Dossier::where('id', $dossier_id)->exists() ?
$dossier_id : (in_array($dossier_id, [-1, 0]) ? $dossier_id : -1))
);
}
// * Recherche favorite
if ($recherche) {
/** @var object */
$filters = $recherche->filters;
/** @var \App\Models\Sujet */
$sujet = $recherche->sujet;
$dossier_id = $recherche->dossier_id;
$textSearch = $recherche->libelle;
}
return view('media_manager')->with([
'sujets' => $sujets,
'typesmedia' => $typesmedia,
'langues' => $langues,
'copyrights' => $copyrights,
'etiquettes' => $etiquettes,
'societes' => $societes,
'marques' => $marques,
'currentFolder' => Dossier::query()->where('id', $dossier_id)->first() ?? $dossier_id,
'currentSujet' => optional($sujet)->codeSujet ?? \optional($sujets->first())->codeSujet,
'currentFilters' => json_encode($filters),
'paniers' => $paniers,
'textSearch' => $textSearch
]);
}
/**
* Show media
*
* @param Media $media
* @return \Illuminate\Http\RedirectResponse
*/
public function show(Media $media): RedirectResponse
{
return redirect()->route('media_manager')->with('autoOpen', $media);
}
/**
* Chargement des médias
*
* @param \App\Http\Requests\Bo\LoadMediaRequest $request
* @param \App\Models\Sujet $sujet
* @return \Illuminate\Http\JsonResponse
*/
public function loadMedia(LoadMediaRequest $request, Sujet $sujet): JsonResponse
{
/** @var \App\Models\User */
$user = auth()->user();
/** @var \App\Models\Dossier|null */
$dossier = Dossier::query()
->with('dossierParent')
->where('id', $request->input('folder'))
->first();
$response = [];
$filters = (object)collect($request->input('filters'))->all();
/** @var boolean Est un dossier Dépot ? */
$isDepot = !empty($dossier) && (\optional($dossier->dossierParent)->id === 1 || $dossier->id === 1);
/**
* Elastic Search must conditions
* @var array
*/
$esMust = [];
/**
* Elastic Search must not conditions
* @var array
*/
$esMustNot = [];
/**
* Elastic Search should conditions
* @var array
*/
$esShould = [];
/**
* Elastic Search filters conditions
* @var array
*/
$esFilters = [];
/** @var string 'created_at' or 'updated_at' or 'version' or 'libelle.keyword' */
$orderField = collect($filters)->reduce(function (string|null $carry, array $item) {
$item = collect($item);
return $carry ?? ($item->get('order') ? $item->get('value') : null);
}) ?? 'created_at';
/** @var string 'asc' or 'desc' */
$order = collect($filters)->reduce(function (string|null $carry, array $item) {
return $carry ?? collect($item)->get('order');
}) ?? 'desc';
/** @var string|null */
$searchText = collect($filters)->reduce(function (string|null $carry, array $item) {
$item = collect($item);
return $carry ?? ($item->get('type') === 'search' ? $item->get('value') : null);
});
$this->esFolderSearch(
$esMust,
$esMustNot,
$esShould,
$request,
$dossier,
$sujet,
$isDepot
);
$this->esTextSearch($esMust, $request, $sujet, $searchText);
$this->esFilters($esMust, $request);
$query = \array_undot([
'bool.must' => $esMust,
'bool.must_not' => $esMustNot,
'bool.should' => $esShould,
'bool.filter' => $esFilters,
]);
$sort = [[$orderField => ['order' => $order]]];
Arr::set($response, 'data', Media::searchByQuery(
$query,
null,
null,
intval($request->post('limit', 50)),
intval($request->post('offset', 0)),
$sort
));
Arr::set($response, 'draggable', $user->hasRole([
config('roles.const.ADMIN'),
config('roles.const.REDACTEUR')
]));
Arr::set($response, 'isDepot', $isDepot);
Arr::set(
$response,
'isCAQuery',
$searchText &&
strpos($searchText, '=') !== false &&
\strval(collect(explode('=', $searchText))->get(0)) === 'ca'
);
Arr::set($response, 'role', $user->role);
return \response()->json($response);
}
/**
* Déplacement des médias
*
* @param \App\Http\Requests\Bo\Ajax\MoveMediaRequest $request
* @return \Illuminate\Http\JsonResponse
*/
public function moveMedia(MoveMediaRequest $request): JsonResponse
{
/** @var \App\Models\User */
$user = auth()->user();
$user->authorizeRoles([
config('roles.const.ADMIN'),
config('roles.const.REDACTEUR')
]);
/** @var \Illuminate\Database\Eloquent\Collection<\App\Models\Media> */
$mediaList = Media::whereIn('id', collect($request->mediaList)->pluck('id'))
->where('isLocked', false)->get();
$destinationDossierId = \intval($request->dossier_id);
// * Update each Media dossier id than try to dispatch media moved event
$mediaList->map(function (Media $media) use ($destinationDossierId, $user) {
$media->dossier_id = $destinationDossierId > 0 ? $destinationDossierId : null;
if (!$media->saveQuietly()) {
throw new \RuntimeException('Failed to save Media');
}
/** @throws \RuntimeException */
$media->addToElasticSearch();
MediaMoved::dispatch($user, $media);
});
return \response()->json(true);
}
/**
* Supprimer des médias
*
* @param \App\Http\Requests\Bo\Ajax\DeleteMediaRequest $request
* @return \Illuminate\Http\JsonResponse
*/
public function removeMedia(DeleteMediaRequest $request): JsonResponse
{
$deletedMediasList = [];
/** @var \App\Models\User */
$user = auth()->user();
$user->authorizeRoles([
config('roles.const.ADMIN'),
config('roles.const.REDACTEUR')
]);
if ($user->hasRole(config('roles.const.ADMIN'))) {
/** @var \Illuminate\Database\Eloquent\Collection<\App\Models\Media> */
$mediaCollection = Media::whereIn('id', $request->mediaList)->get();
} else {
/** @var \Illuminate\Database\Eloquent\Collection<\App\Models\Media> */
$mediaCollection = Media::whereIn('id', $request->mediaList)->whereNull('arcadia_id')->get();
}
DB::transaction(function () use ($mediaCollection, &$deletedMediasList) {
$mediaCollection->map(function (Media $media) use (&$deletedMediasList) {
$deletedMediasList[] = $media->id;
$media->deleteOrFail();
});
});
return response()->json($deletedMediasList);
}
/**
* Récupération d'un média
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\JsonResponse
*/
public function recoverMedia(Request $request): JsonResponse
{
try {
return DB::transaction(function () use ($request) {
/** @var \App\Models\Media */
$media = Media::onlyTrashed()
->where('arcadia_id', '=', $request->arcadia_id)
->firstOrFail();
if (!$media->restore()) {
throw new \RuntimeException('Failed to restore media');
}
/** @throws \RuntimeException */
$media->addToElasticSearch();
// * Lien Arcadia
if (!($status = ArcadiaLinkUtilities::reactivate($media))) {
throw new \RuntimeException('Failed to restore media arcadia link');
}
return response()->json($status);
});
} catch (ModelNotFoundException | \RuntimeException $e) {
return response()->json($e->getMessage(), 500);
} //end try
}
/**
* Mets à jour toutes les informations d'un média
*
* @param \App\Http\Requests\Bo\Ajax\UpdateMediaRequest $request
* @param \App\Models\Media $media
* @return \Illuminate\Http\JsonResponse
*/
public function updateMedia(UpdateMediaRequest $request, Media $media): JsonResponse
{
/** @var \App\Models\User */
$user = auth()->user();
$user->authorizeRoles([
config('roles.const.ADMIN'),
config('roles.const.REDACTEUR'),
config('roles.const.CONTRIBUTEUR')
]);
if ($media->isLocked) {
return \response()->json([
'status' => false,
'error' => trans('Le média est en attente d\'un retour d\'Arcadia.')
]);
}
try {
DB::transaction(function () use ($request, $media) {
$media->fill($request->validated());
// MAJ des tags .
$media->tags()->detach();
collect($request->tags)->map(function (array $tag) use ($media) {
/** @var \App\Models\Tag */
$oTag = Tag::where('libelle', $tag['libelle'])->firstOrNew();
$oTag->libelle = $tag['libelle'];
$oTag->saveOrFail();
$media->tags()->attach($oTag);
});
// ---- Les sociétés
$media->societes()->sync(collect($request->societes)->pluck('id')->all());
// ---- Les marques
$media->marques()->sync(collect($request->marques)->pluck('codMarq')->all());
// ---- Les articles
$media->articles()->sync(collect($request->articles)->pluck('id')->all());
$media->saveOrFail();
$media->fresh();
$media->addToElasticSearch();
});
$media->fresh();
return \response()->json([
'status' => true,
'sujet_id' => $media->sujet_id,
'datas' => $media
]);
} catch (\RuntimeException $e) {
report($e);
return \response()->json([
'status' => false,
'error' => trans('Une erreur est survenue veuillez réessayer')
]);
} //end try
}
/**
* Duplique un média sans l'image
* @param \App\Models\Media $media
* @return \Illuminate\Http\JsonResponse
* @throws \RuntimeException If copying default picture or get defaultPicture informations fails.
*/
public function duplicateMedia(Media $media): JsonResponse
{
return DB::transaction(function () use ($media) {
/** @var \App\Models\User */
$user = auth()->user();
$user->authorizeRoles([
config('roles.const.ADMIN'),
config('roles.const.REDACTEUR'),
config('roles.const.CONTRIBUTEUR')
]);
if ($media->isLocked) {
return \response()->json([
'status' => false,
'error' => trans('Le média est en attente d\'un retour d\'Arcadia.')
]);
}
$clonedMedia = $media->replicate();
// * Remove Arcadia ID (cloned is not linked to arcadia)
$clonedMedia->arcadia_id = null;
/** @var \Illuminate\Filesystem\FilesystemAdapter */
$storage = Storage::disk('media');
$clonedMedia->uid = Str::uuid();
$clonedMedia->extension = MediaExtension::jpg;
if (!Storage::exists('assets/images/default.jpg')) {
throw new \RuntimeException('Missing default picture');
}
$fileContent = Storage::get('assets/images/default.jpg');
if (!$storage->put($clonedMedia->relative_path, $fileContent)) {
throw new \RuntimeException('Failed to copy default picture');
}
$clonedMedia->libelle = Str::limit("{$clonedMedia->libelle}_copy", 45);
$clonedMedia->taille = \strlen($fileContent);
$dimensions = ToolboxHelper::getImageDimensions(Storage::path('assets/images/default.jpg'));
if ($dimensions) {
$clonedMedia->resolution = $dimensions['resolutionX'];
$clonedMedia->largeur = $dimensions['width'];
$clonedMedia->hauteur = $dimensions['height'];
$clonedMedia->largeur_mm = !empty($media->resolution) ? ceil($media->largeur * 10) : 0;
$clonedMedia->hauteur_mm = !empty($media->resolution) ? ceil($media->hauteur * 10) : 0;
}
$clonedMedia->isDefault = true;
$clonedMedia->owner()->associate($user);
$clonedMedia->typeMedia()->associate(TypeMedia::getMediaType($clonedMedia->extension));
// ---- Creation des vignettes de base
$clonedMedia->createThumbnail();
// ---- Creation des vignettes en lien avec le sujet du média
$clonedMedia->createSubjectThumbnails();
$clonedMedia->save();
// * Add relations after having a media id
$media->articles->map(function (Article $article) use ($clonedMedia) {
$clonedMedia->articles()->attach($article);
});
$media->marques->map(function (Marque $marque) use ($clonedMedia) {
$clonedMedia->marques()->attach($marque);
});
$media->societes->map(function (Societe $societe) use ($clonedMedia) {
$clonedMedia->societes()->attach($societe);
});
$media->tags->map(function (Tag $tag) use ($clonedMedia) {
$clonedMedia->tags()->attach($tag);
});
/** @throws \RuntimeException */
$clonedMedia->addToElasticSearch();
// * Get props inserted by DB.
$clonedMedia->refresh();
return \response()->json([
'status' => true,
'sujet_id' => $clonedMedia->sujet_id,
'datas' => $clonedMedia
]);
});
}
/**
* Sauvegarde toutes les informations d'un média
*
* @param \App\Http\Requests\Bo\Ajax\ApplyStickerRequest $request
* @return \Illuminate\Http\JsonResponse
*/
public function applySticker(ApplyStickerRequest $request): JsonResponse
{
/** @var \App\Models\User */
$user = auth()->user();
$user->authorizeRoles([
config('roles.const.ADMIN'),
config('roles.const.REDACTEUR'),
config('roles.const.CONTRIBUTEUR')
]);
/** @var \Illuminate\Database\Eloquent\Collection<\App\Models\Media> */
$mediaList = Media::whereIn('id', collect($request->mediaList)->pluck('id'))->get();
/** @var \App\Models\Etiquette */
$etiquette = Etiquette::where('etiquette_id', $request->etiquette_id)->firstOrFail();
DB::transaction(function () use ($mediaList, $etiquette) {
$mediaList->map(
function (Media $media) use ($etiquette) {
if ($media->isLocked) {
throw ValidationException::withMessages([
'media' => 'Impossible d\'appliquer la demande un des médias est verrouilé'
]);
}
$media->etiquette()->associate($etiquette);
$media->saveOrFail();
}
);
});
return response()->json();
}
/**
* Vérification des clés pour liaison arcadia avant création et mise à jour
*
* @param \App\Http\Requests\Bo\Ajax\CheckRefKeyRequest $request
* @return \Illuminate\Http\JsonResponse
* @throws \RuntimeException If media does not have a subject.
*/
public function checkRefKey(CheckRefKeyRequest $request): JsonResponse
{
/** @var \App\Models\User */
$user = auth()->user();
$user->authorizeRoles([config('roles.const.ADMIN')]);
/** @var \App\Models\Media */
$media = $request->media;
// ? Media has subject ?
if (!$media->sujet) {
throw new \RuntimeException("Le media '{$media->id}' n'as pas de sujet");
}
// ? Subject is not arcadia ?
if (!$media->sujet->sujet_arcadia) {
return \response()->json(ArcadiaLinkUtilities::getRefKey($media)->count() > 0);
}
// * On est sur un sujet arcadia (donc pas le sujet Groupe par exemple) .
// ! restreindre pour tout sauf si type de vue 19 (BAT) et sujet 1 (Articles)
if (\optional($media->typeVue)->id === 19 and \optional($media->sujet)->id === 1) {
return \response()->json(ArcadiaLinkUtilities::getRefKey($media)->count() > 0);
}
// * On récupère les restrictions par arcadia.
/** @var string|null */
$checkwidth = Setting::where('key', 'arcadia_size_restriction_width')->value('value');
/** @var string|null */
$checkheight = Setting::where('key', 'arcadia_size_restriction_height')->value('value');
/** @var string|null */
$checkmime = Setting::where('key', 'arcadia_mime_restriction')->value('value');
/** @var string[] */
$checkmime = $checkmime ? \explode(',', $checkmime) : [];
// * Vérification du mime .
if (!(in_array($media->extension->value, $checkmime) || empty($checkmime))) {
// * fail type de fichier
return \response()->json([
'status' => false,
'error' => "Le type de fichier doit être " . implode('ou ', $checkmime) .
", veuillez charger un autre média"
]);
}
// * Verification de la largeur (hard default 1800)
// * Vérification hauteur (hard default 1800)
if (
!($media->largeur == $checkwidth || $media->largeur === 1800 || \is_null($checkwidth)) or
!($media->hauteur == $checkheight || $media->hauteur === 1800 || \is_null($checkheight))
) {
// * fail largeur
return \response()->json([
'status' => false,
'error' =>
"Les dimensions requises sont ${checkwidth}px par ${checkheight}px, veuillez charger un autre média"
]);
}
return \response()->json();
}
/**
* Applique un Id Arcadia à un média
*
* @param \App\Models\Media $media
* @return \Illuminate\Http\JsonResponse
* @throws \Illuminate\Validation\ValidationException If the media is already linked to Arcadia.
*/
public function createArcadiaLink(Media $media): JsonResponse
{
/** @var \App\Models\User */
$user = auth()->user();
$user->authorizeRoles([config('roles.const.ADMIN')]);
if ($media->arcadia_id) {
throw ValidationException::withMessages([
'media' => trans('Ce média est déjà lié à arcadia')
]);
}
MediaLinkWithArcadia::dispatch($user, $media);
return response()->json(true);
}
/**
* Téléchargement des médias pour panier publics
*
* @param \App\Http\Requests\Bo\DownloadMediaPublicRequest $request
* @param \App\Models\Format|null $format
* @return \Symfony\Component\HttpFoundation\BinaryFileResponse
*/
public function downloadMediaPublic(
DownloadMediaPublicRequest $request,
Format|null $format = null
): BinaryFileResponse {
return $this->downloadMedia($request, $format);
}
/**
* Téléchargement des médias
*
* @param \App\Http\Requests\Bo\DownloadMediaRequest $request
* @param \App\Models\Format|null $format
* @return \Symfony\Component\HttpFoundation\BinaryFileResponse
*/
public function downloadMedia(DownloadMediaRequest $request, Format|null $format = null): BinaryFileResponse
{
$deleteFileAfterSend = false;
$mediaIds = collect($request->mediaList);
if ($mediaIds->count() === 1) {
/** @var \App\Models\Media */
$media = Media::whereIn('id', $mediaIds)->firstOrFail();
/** @var \Illuminate\Filesystem\FilesystemAdapter */
$storage = Storage::disk('media');
$fp = !$format ? $storage->path($media->relative_path) : $media->getPath($format);
if (!File::exists($fp)) {
abort(404, 'Fichier inconnu.');
}
$dlFileName = str_replace(' ', '_', Str::slug($media->libelle));
$ext = pathinfo($fp, PATHINFO_EXTENSION);
if (!$format) {
return response()
->download($fp, "{$dlFileName}_original_{$media->largeur}x{$media->hauteur}px.{$ext}")
->deleteFileAfterSend($deleteFileAfterSend);
}
return response()
->download($fp, "{$dlFileName}_{$format->libelle}_{$media->largeur}x{$media->hauteur}px.{$ext}")
->deleteFileAfterSend($deleteFileAfterSend);
} //end if
/** @var \Illuminate\Filesystem\FilesystemAdapter */
$storage = Storage::disk('public');
$uniqId = uniqid();
$date = date("Ymd");
// * Create zip archive .
$zip_file = $storage->path("zips/DAM_{$uniqId}_{$date}.zip");
$zip = new \ZipArchive();
$zip->open($zip_file, \ZipArchive::CREATE | \ZipArchive::OVERWRITE);
/** @var \Illuminate\Filesystem\FilesystemAdapter */
$storage = Storage::disk('media');
// * Add file to archive.
foreach ($mediaIds as $mediaId) {
/** @var \App\Models\Media */
$media = Media::where('id', $mediaId)->firstOrFail();
$fp = !$format ? $storage->path($media->relative_path) : $media->getPath($format);
if (!File::exists($fp)) {
$zip->close();
abort(404, 'Fichier inconnu.');
}
$dlFileName = str_replace(' ', '_', Str::slug($media->libelle));
$ext = pathinfo($fp, PATHINFO_EXTENSION);
$dlFileName = !$format ?
"{$dlFileName}_original_{$media->largeur}x{$media->hauteur}px.{$ext}" :
"{$dlFileName}_{$format->libelle}_{$media->largeur}x{$media->hauteur}px.{$ext}";
$zip->addFile($fp, $dlFileName);
} //end foreach
$deleteFileAfterSend = true;
$zip->close();
$fp = $zip_file;
return response()->download($fp)->deleteFileAfterSend($deleteFileAfterSend);
}
/**
* Renvoie les infos complémentaires d'un média
*
* @param \App\Models\Media $media
* @return \Illuminate\Http\JsonResponse
*/
public function getMediaOtherInfos(Media $media): JsonResponse
{
if (!auth()->check()) {
abort(401, 'Cette action n\'est pas autorisée.');
}
$history = Historique::query()
->whereHas('media', fn(Builder $q) => $q->where('id', $media->id))
->with('user')
->orderBy('created_date', 'DESC')
->get();
return \response()->json([
'history' => $history,
'vignettes' => $this->getVignettesByMedia($media)
]);
}
// * PRIVATE METHODS
/**
* Elastic Search filters
*
* @param array $esMust
* @param \App\Http\Requests\Bo\LoadMediaRequest $request
* @return void
*/
private function esFilters(array &$esMust, LoadMediaRequest $request): void
{
$filters = (object)collect($request->filters)->all();
$getFilterProp = function ($prop) use ($filters) {
return collect($filters)->reduce(function (array|null $carry, array $item) use ($prop) {
$item = collect($item);
return $carry ?? ($item->get('type') === $prop ? $item->get('value') : null);
});
};
/** @var array|null */
$codeTypemedia = $getFilterProp('type_media_id');
/** @var array|null */
$codeTypevue = $getFilterProp('type_vue_id');
/** @var array|null */
$etiquette_id = $getFilterProp('etiquette_id');
/** @var boolean */
$arcadia_id = collect($filters)->reduce(function (string|null $carry, array $item) {
$item = collect($item);
return $carry ?? ($carry or $item->get('type') === 'arcadia_id' ? true : false);
});
$esConditions = [];
// * Filtre liason avec Arcadia
if ($arcadia_id) {
$esConditions[] = \array_undot(['exists.field' => 'arcadia_id']);
}
// * Filtre type de média
if ($codeTypemedia) {
$esConditions[] = \array_undot(['bool.filter.terms.type_media_id' => collect($codeTypemedia)
->pluck('codeTypemedia')->values()->all()]);
}
// * Filtre type de vue
if ($codeTypevue) {
$esConditions[] = \array_undot(['bool.filter.terms.type_vue_id' => collect($codeTypevue)
->pluck('codeTypevue')->values()->all()]);
}
// * Filtre etiquette
if ($etiquette_id) {
$esConditions[] = \array_undot(['bool.filter.terms.etiquette_id' => collect($etiquette_id)
->pluck('etiquette_id')->values()->all()]);
}
$esMust = array_merge($esMust, $esConditions);
}
/**
* Elastic Search select appropriate Folder
*
* @param array $esMust ES conditions INCLURE TOUT (AND).
* @param array $esMustNot ES conditions EXCLURE.
* @param array $esShould ES conditions INCLURE AU MOINS (OR), avec un score.
* @param \App\Http\Requests\Bo\LoadMediaRequest $request La request Lrvl.
* @param \App\Models\Dossier|null $dossier Le dossier concerné, si les Medias
* doivent appartenir a celui-ci.
* @param \App\Models\Sujet $sujet Le sujet concerné, si les Medias
* doivent appartenir a celui-ci.
* @param boolean $isDepot Si les medias doivent se trouver dans le dossier dépot.
* @return void
*/
private function esFolderSearch(
array &$esMust,
array &$esMustNot,
array &$esShould,
LoadMediaRequest $request,
Dossier|null $dossier,
Sujet $sujet,
bool $isDepot
): void {
/** @var \App\Models\User */
$user = auth()->user();
// ? Doivent être dans le dossier dépot ?
if ($isDepot) {
// * Dossier dépôt
$esMust = array_merge($esMust, [[
\array_undot(['match.dossier_id' => $dossier->id])
]]);
return;
}
// ? N'est pas dans le dossier dépot ou racine ?
if (!$dossier) {
// ? Recherche globale ?
if ($request->input('folder') === -1) {
// * Recherche globale .
$esMust = array_merge($esMust, [
// * AND
\array_undot(['bool.must.match.sujet_id' => $sujet->codeSujet])
]);
} else {
// * Dossier racine .
$esMust = array_merge($esMust, [
// * AND
\array_undot(['bool.should.match.sujet_id' => $sujet->codeSujet])
]);
$esMustNot = array_merge($esMustNot, [
\array_undot(['exists.field' => 'dossier_id'])
]);
} //end if
// * OR
$esShould = array_merge($esShould, [
\array_undot(['match.statut' => MediaStatut::public_etendu]),
\array_undot(['match.statut' => MediaStatut::public]),
\array_undot(['match.created_by' => $user->id])
]);
return;
} //end if
// * Dossier classic .
$esMust = array_merge($esMust, [[
// * AND
\array_undot([
'bool.must' => [
\array_undot(['match.sujet_id' => $sujet->codeSujet]),
\array_undot(['match.dossier_id' => $dossier->id]),
]
])
]]);
// ? User n'est pas ADMIN ?
if (!$user->hasRole(config('roles.const.ADMIN'))) {
// * Ajout de restrictions
// * Tout ce qui nous appartient et tout ce qui n'est pas brouillon
$esMust = array_merge($esMust, [
\array_undot([
// * OR
'bool.should' => [
\array_undot([
'bool.must_not' => [[
\array_undot([
'term.statut.value' => MediaStatut::brouillon,
'term.statut.boost' => 1.0
])
]],
'bool.adjust_pure_negative' => true,
'bool.boost' => 1.0
]),
\array_undot([
'term.created_by.value' => $user->id,
'term.created_by.boost' => 1.0
])
],
'bool.adjust_pure_negative' => true,
'bool.boost' => 1.0
])
]);
} //end if
}
/**
* Elastic Search Recherche texte
*
* eg : 'cv = 5010' OU 'poulet + certifie' OU 'nimporte quoi'.
*
* 'ca' => 'articles.noArt',
* 'fv' => 'articles.codFamVte',
* 'gca' => 'articles.codGencodAdm',
* 'gcs' => 'articles.codGencodSymb',
* 'gcp' => 'articles.codGencodPds',
* 'cd' => 'id',
* 'cv' => 'arcadia_id',
*
* @param array $esMust
* @param \App\Http\Requests\Bo\LoadMediaRequest $request
* @param \App\Models\Sujet $sujet
* @param string|null $searchText
* @return void
*/
private function esTextSearch(
array &$esMust,
LoadMediaRequest $request,
Sujet $sujet,
string|null $searchText
): void {
if (!$searchText) {
return;
}
$tmpFilters = [];
$search = strtolower(trim($searchText));
// * Search mode columns
if (strpos($search, '=') !== false) {
$tmpSearch = collect(explode('=', $search));
$key = \strval($tmpSearch->get(0));
$needle = \strval($tmpSearch->get(1));
$matches = [
'ca' => 'articles.noArt',
'fv' => 'articles.codFamVte',
'gca' => 'articles.codGencodAdm',
'gcs' => 'articles.codGencodSymb',
'gcp' => 'articles.codGencodPds',
'cd' => 'id',
'cv' => 'arcadia_id',
];
if (\array_key_exists($key, $matches)) {
$tmpFilters = [[
\array_undot(['bool.must.match' => [
$matches[$key] => $needle
]])
]];
}
// * Search keywords
} elseif (strpos($search, '+') !== false) {
$tmpSearch = explode('+', $search);
$mustLib = [];
foreach ($tmpSearch as $search) {
array_push($mustLib, [
'wildcard' => [
'libelle.keyword' => [
'wildcard' => "*$search*",
'boost' => 1.0
]
]
]);
}
$mustArt = [];
foreach ($tmpSearch as $search) {
array_push($mustArt, [
'wildcard' => [
'articles.libCcial.keyword' => [
'wildcard' => "*$search*",
'boost' => 1.0
]
]
]);
}
$tmpFilters = [
\array_undot(['bool.should' => [
\array_undot(['bool.must' => $mustLib]),
\array_undot(['bool.must' => $mustArt])
]])
];
} else {
// * Search auto
$tmpFilters = [[
'multi_match' => [
'query' => $search,
"type" => "most_fields",
'fields' => [
'libelle^3',
'commentaire^2',
'arcadia_id',
'articles.libCcial',
'articles.libMarq',
'articles.libFamVte',
'tags.libelle'
],
'operator' => 'or',
'fuzziness' => 'AUTO'
]
]];
} //end if
$esMust = array_merge($esMust, $tmpFilters);
/** @var \App\Models\User */
$user = auth()->user();
$filters = (object)collect($request->filters)->all();
MediaSearched::dispatch(
$user,
$sujet,
$searchText,
$filters,
intval($request->folder)
);
}
/**
* Get vignettes info from media
*
* @param \App\Models\Media $media
* @return array
*/
private function getVignettesByMedia(Media $media): array
{
/** @var \Illuminate\Filesystem\FilesystemAdapter */
$storage = Storage::disk('media');
$vignettes = [];
$vignettes['original'] = [
'url' => $storage->url($media->relative_path),
'extension' => $media->extension->value,
'largeur' => $media->largeur,
'hauteur' => $media->hauteur
];
$sys_extension = in_array($media->extension, [
MediaExtension::pdf,
MediaExtension::ai,
MediaExtension::psd
]) ? MediaExtension::png : $media->extension->value;
$vignettes['preview'] = [
'url' => $storage->url($media->preview_relative_path),
'extension' => $sys_extension,
'largeur' => '1800',
'hauteur' => '1800'
];
$vignettes['thumb'] = [
'url' => $storage->url($media->thumb_relative_path),
'extension' => $sys_extension,
'largeur' => '200',
'hauteur' => '200'
];
$media->sujet->formats->map(function (Format $format) use (&$vignettes, $media, $storage) {
$vignettes[$format->libelle] = [
'url' => $storage->url("{$media->folder}/{$media->uid}_{$format->libelle}.{$format->extension}"),
'extension' => $format->extension,
'largeur' => $format->largeur,
'hauteur' => $format->hauteur
];
});
return $vignettes;
}
}