diff --git a/app/Http/Controllers/RicercaController.php b/app/Http/Controllers/RicercaController.php new file mode 100644 index 00000000..4b6e7b64 --- /dev/null +++ b/app/Http/Controllers/RicercaController.php @@ -0,0 +1,58 @@ +authorizeRead('individui'); + + $allTags = Tag::orderBy('name')->get(); + + $tagSlugs = (array) $request->input('tag', []); + + if (empty($tagSlugs)) { + return view('ricerca.index', compact('allTags')); + } + + $tagSlugs = array_filter($tagSlugs); + $selectedTags = Tag::whereIn('slug', $tagSlugs)->get(); + + $results = []; + $totals = []; + + if (count($tagSlugs) === 1) { + $tag = $selectedTags->first(); + $results['individui'] = $tag->individui()->orderBy('cognome')->orderBy('nome')->get(); + $results['gruppi'] = $tag->gruppi()->orderBy('nome')->get(); + $results['eventi'] = $tag->eventi()->orderBy('data_specifica')->orderBy('nome_evento')->get(); + $results['documenti'] = $tag->documenti()->orderBy('nome_file')->get(); + $results['mailingLists'] = $tag->mailingLists()->orderBy('nome')->get(); + } else { + $results['individui'] = Individuo::withAllTags($tagSlugs)->orderBy('cognome')->orderBy('nome')->get(); + $results['gruppi'] = Gruppo::withAllTags($tagSlugs)->orderBy('nome')->get(); + $results['eventi'] = Evento::withAllTags($tagSlugs)->orderBy('data_specifica')->orderBy('nome_evento')->get(); + $results['documenti'] = Documento::withAllTags($tagSlugs)->orderBy('nome_file')->get(); + $results['mailingLists'] = MailingList::withAllTags($tagSlugs)->orderBy('nome')->get(); + } + + $totals = [ + 'individui' => $results['individui']->count(), + 'gruppi' => $results['gruppi']->count(), + 'eventi' => $results['eventi']->count(), + 'documenti' => $results['documenti']->count(), + 'mailingLists' => $results['mailingLists']->count(), + ]; + + return view('ricerca.index', compact('selectedTags', 'tagSlugs', 'results', 'totals', 'allTags')); + } +} diff --git a/app/Models/Tag.php b/app/Models/Tag.php new file mode 100644 index 00000000..0a927734 --- /dev/null +++ b/app/Models/Tag.php @@ -0,0 +1,62 @@ + 'integer', + ]; + + protected static function boot(): void + { + parent::boot(); + + static::creating(function (self $tag) { + if (empty($tag->slug)) { + $tag->slug = str()->slug($tag->name); + } + }); + } + + public function individui(): MorphToMany + { + return $this->morphedByMany(Individuo::class, 'taggable'); + } + + public function gruppi(): MorphToMany + { + return $this->morphedByMany(Gruppo::class, 'taggable'); + } + + public function eventi(): MorphToMany + { + return $this->morphedByMany(Evento::class, 'taggable'); + } + + public function documenti(): MorphToMany + { + return $this->morphedByMany(Documento::class, 'taggable'); + } + + public function mailingLists(): MorphToMany + { + return $this->morphedByMany(MailingList::class, 'taggable'); + } + + public function getCountAttribute(): int + { + return $this->individui()->count() + + $this->gruppi()->count() + + $this->eventi()->count() + + $this->documenti()->count() + + $this->mailingLists()->count(); + } +} diff --git a/app/Traits/HasTagsLight.php b/app/Traits/HasTagsLight.php new file mode 100644 index 00000000..841d8d04 --- /dev/null +++ b/app/Traits/HasTagsLight.php @@ -0,0 +1,30 @@ +morphToMany(Tag::class, 'taggable'); + } + + public function scopeWithAllTags($query, array $tags) + { + foreach ($tags as $tag) { + $query->whereHas('tags', fn ($q) => $q->where('slug', $tag)); + } + + return $query; + } + + public function scopeWithAnyTags($query, array $tags) + { + $query->whereHas('tags', fn ($q) => $q->whereIn('slug', $tags)); + + return $query; + } +} diff --git a/database/migrations/2026_06_08_194155_create_tags_tables.php b/database/migrations/2026_06_08_194155_create_tags_tables.php new file mode 100644 index 00000000..1a9313e9 --- /dev/null +++ b/database/migrations/2026_06_08_194155_create_tags_tables.php @@ -0,0 +1,38 @@ +id(); + $table->string('name', 100); + $table->string('slug', 100)->unique(); + $table->string('color', 7)->nullable(); + $table->integer('order_column')->default(0); + $table->timestamps(); + }); + } + + if (!Schema::hasTable('taggables')) { + Schema::create('taggables', function (Blueprint $table) { + $table->foreignId('tag_id')->constrained()->cascadeOnDelete(); + $table->morphs('taggable'); + $table->primary(['tag_id', 'taggable_id', 'taggable_type']); + }); + } + } + + public function down(): void + { + Schema::dropIfExists('taggables'); + Schema::dropIfExists('tags'); + } +}; diff --git a/resources/views/partials/_tag-filter-bar.blade.php b/resources/views/partials/_tag-filter-bar.blade.php new file mode 100644 index 00000000..3a602076 --- /dev/null +++ b/resources/views/partials/_tag-filter-bar.blade.php @@ -0,0 +1,34 @@ +@php + $filterTags = $filterTags ?? (\App\Models\Tag::orderBy('name')->get()); + $activeTags = (array) request('tag', []); +@endphp +@if($filterTags->isNotEmpty()) +
+@endif diff --git a/resources/views/partials/_tag-selector.blade.php b/resources/views/partials/_tag-selector.blade.php new file mode 100644 index 00000000..0f34714b --- /dev/null +++ b/resources/views/partials/_tag-selector.blade.php @@ -0,0 +1,123 @@ +@php + $allTags = $allTags ?? \App\Models\Tag::orderBy('name')->get(); + $selectedTags = old('tags', $selectedTags ?? []); + $tagFieldName = $tagFieldName ?? 'tags'; + $selectorId = 'tag-selector-' . md5($tagFieldName); + $selectedTagObjects = $allTags->whereIn('id', $selectedTags); +@endphp + +Nessun tag disponibile. Crea i tag nelle Impostazioni.
+ @endif + +Clicca sui tag per selezionarli (Ctrl+click per più tag).
+ + @else +