Skip to content

Commit fe08fda

Browse files
authored
Merge pull request #6 from andreazorzi/development
Refactor Search Table and add multiple qrcode download
2 parents 074596b + e415545 commit fe08fda

File tree

8 files changed

+165
-59
lines changed

8 files changed

+165
-59
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
/public/build
44
/public/hot
55
/public/storage
6+
/public/tmp
67
/storage/*.key
78
/vendor
89
.env

app/Http/Controllers/ShortController.php

Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,18 @@
22

33
namespace App\Http\Controllers;
44

5+
use ZipArchive;
56
use App\Models\Tag;
67
use App\Classes\Help;
78
use App\Models\Short;
89
use App\Jobs\VisitCountry;
10+
use Illuminate\Support\Str;
911
use Illuminate\Http\Request;
1012
use chillerlan\QRCode\QRCode;
1113
use Illuminate\Validation\Rule;
1214
use chillerlan\QRCode\QROptions;
13-
use Illuminate\Support\Facades\Storage;
15+
use chillerlan\QRCode\Data\QRMatrix;
16+
use chillerlan\QRCode\Common\EccLevel;
1417
use Illuminate\Support\Facades\Validator;
1518
use Brunoinds\LinkPreviewDetector\LinkPreviewDetector;
1619

@@ -104,6 +107,7 @@ public function share(Request $request, Short $short){
104107
public function qrcode(Request $request, Short $short){
105108
$options = new QROptions;
106109
$options->quietzoneSize = 1;
110+
107111
$contents = (new QRCode($options))->render($short->getLink());
108112
$path = $short->code.".svg";
109113

@@ -198,4 +202,41 @@ public function upload_csv(Request $request){
198202

199203
// return view("components.backoffice.modals.short-upload-csv", ["lines" => $lines]);
200204
}
205+
206+
public function multiple_download(Request $request){
207+
$shorts = Short::filter([
208+
"query" => $request->filter ?? null,
209+
"advanced_search" => $request->advanced_search ?? null,
210+
])->get();
211+
212+
$time = time();
213+
$zip = new ZipArchive;
214+
$zipFileName = "tmp/qrcode/".$time.".zip";
215+
$zip->open(public_path($zipFileName), ZipArchive::CREATE);
216+
217+
foreach($shorts as $short){
218+
$options = new QROptions;
219+
$options->quietzoneSize = 1;
220+
221+
if(!empty($request->logo)){
222+
$options->eccLevel= EccLevel::H;
223+
$options->addLogoSpace = true;
224+
$options->logoSpaceWidth = 10;
225+
$options->logoSpaceHeight = 10;
226+
$options->keepAsSquare = [
227+
QRMatrix::M_FINDER_DARK,
228+
QRMatrix::M_FINDER_DOT,
229+
QRMatrix::M_ALIGNMENT_DARK,
230+
];
231+
}
232+
233+
$contents = (new QRCode($options))->render($short->getLink());
234+
235+
$zip->addFromString(Str::slug($short->description).".svg", base64_decode(str_replace("data:image/svg+xml;base64,", "", $contents)));
236+
}
237+
238+
$zip->close();
239+
240+
return response(headers: ["HX-Redirect" => asset($zipFileName)]);
241+
}
201242
}

app/Models/Short.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
use DateTime;
66
use App\Rules\Slug;
7+
use App\Traits\ModelBase;
78
use Illuminate\Support\Str;
89
use Illuminate\Http\Request;
910
use Illuminate\Validation\Rule;
@@ -17,7 +18,7 @@
1718

1819
class Short extends Model
1920
{
20-
use HasFactory;
21+
use HasFactory, ModelBase;
2122

2223
public $timestamps = false;
2324

app/Traits/ModelBase.php

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
<?php
2+
3+
namespace App\Traits;
4+
5+
use App\Classes\Help;
6+
use Illuminate\Http\Request;
7+
use Illuminate\Contracts\View\View;
8+
use Illuminate\Support\Facades\Schema;
9+
10+
trait ModelBase
11+
{
12+
public static function filter($filters, $sort = false){
13+
$query = $filters["query"] ?? "";
14+
$advanced = $filters["advanced_search"] ?? [];
15+
$modelfilter = $filters["modelfilter"] ?? [];
16+
$advanced_values = [];
17+
$fields = self::getTableFields();
18+
19+
foreach($fields as $key => $field){
20+
if(!empty($field["filter"])){
21+
if(!empty($advanced[$key])){
22+
if(($field["advanced-type"] ?? null) == "date-range"){
23+
$dates = explode(" - ", $advanced[$key]);
24+
25+
$filter[] = ($field["custom-filter"] ?? $key)." BETWEEN ? AND ?";
26+
$advanced_values[] = Help::convert_date($dates[0]);
27+
$advanced_values[] = Help::convert_date($dates[1] ?? $dates[0]);
28+
}
29+
else if(($field["advanced-type"] ?? null) == "in-array"){
30+
$multi_filter = [];
31+
32+
foreach($advanced[$key] as $value){
33+
$multi_filter[] = "CONVERT(".($field["custom-filter"] ?? $key)." using 'utf8') LIKE '%".$value."%'";
34+
}
35+
36+
$filter[] = "(".implode(" AND ", $multi_filter).")";
37+
}
38+
else if(($field["advanced-type"] ?? null) == "like"){
39+
$filter[] = "CONVERT(".($field["custom-filter"] ?? $key)." using 'utf8') LIKE '%".$advanced[$key]."%'";
40+
}
41+
else{
42+
$multi_filter = [];
43+
44+
foreach($advanced[$key] as $value){
45+
$multi_filter[] = "CONVERT(".($field["custom-filter"] ?? $key)." using 'utf8') = ?";
46+
$advanced_values[] = $value;
47+
}
48+
49+
$filter[] = "(".implode(" OR ", $multi_filter).")";
50+
}
51+
}
52+
else if(Help::empty_dictionary($advanced)){
53+
$filter[] = "CONVERT(".($field["custom-filter"] ?? $key)." using 'utf8') LIKE ?";
54+
$filter_values[] = "%".$query."%";
55+
}
56+
}
57+
58+
if(!empty($field["sort"])){
59+
$model_sort[] = ($field["custom-filter"] ?? $key)." ".$field["sort"];
60+
}
61+
}
62+
63+
$search = !empty($filter) ? self::whereRaw("(".implode(Help::empty_dictionary($advanced) ? " OR " : " AND ", $filter).")", !Help::empty_dictionary($advanced) ? $advanced_values : $filter_values) : self::query();
64+
65+
// Check model filter
66+
foreach($modelfilter as $key => $value){
67+
$search = $search->whereRaw("CONVERT(".($fields[$key]["custom-filter"] ?? $fields[$key]["key"] ?? $key)." using 'utf8') = ?", $value);
68+
}
69+
70+
if($sort){
71+
$search->orderByRaw(implode(",", $model_sort));
72+
}
73+
74+
return $search;
75+
}
76+
}

resources/views/components/search-table-filters/shorts.blade.php

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,21 @@
99
<i class="fa-brands fa-searchengin"></i>
1010
{{__("app.pages.tags.advanced_search")}}
1111
</button>
12+
13+
<div class="dropdown d-inline-block">
14+
<button class="btn btn-success btn-sm dropdown-toggle w-100" type="button" data-bs-toggle="dropdown" aria-expanded="false">
15+
<i class="fa-solid fa-qrcode me-2"></i>
16+
Download
17+
</button>
18+
<ul class="dropdown-menu">
19+
<li>
20+
<a class="dropdown-item" role="button" hx-get="{{route("short.multiple-download")}}" hx-include="[name='filter'],[name^='advanced_search']">QRCode</a>
21+
</li>
22+
<li>
23+
<a class="dropdown-item" role="button" hx-get="{{route("short.multiple-download", ["logo" => true])}}" hx-include="[name='filter'],[name^='advanced_search']">QRCode + Logo Space</a>
24+
</li>
25+
</ul>
26+
</div>
1227
</div>
1328
<div id="advanced-search" class="row gy-2 d-none">
1429
<div class="col-md-4">
@@ -48,6 +63,13 @@
4863
onChange: function(value) {
4964
$("#page").val(1);
5065
htmx.trigger("#page", "change");
66+
},
67+
onDropdownOpen: function() {
68+
for (const select of $(".selectize.selectized")) {
69+
if(select !== this.$input[0]){
70+
select.selectize.close();
71+
}
72+
}
5173
}
5274
});
5375
@@ -76,6 +98,13 @@
7698
onChange: function(value) {
7799
$("#page").val(1);
78100
htmx.trigger("#page", "change");
101+
},
102+
onDropdownOpen: function() {
103+
for (const select of $(".selectize.selectized")) {
104+
if(select !== this.$input[0]){
105+
select.selectize.close();
106+
}
107+
}
79108
}
80109
});
81110
});

resources/views/components/search-table-filters/users.blade.php

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,13 @@
3737
onChange: function(value) {
3838
$("#page").val(1);
3939
htmx.trigger("#page", "change");
40+
},
41+
onDropdownOpen: function() {
42+
for (const select of $(".selectize.selectized")) {
43+
if(select !== this.$input[0]){
44+
select.selectize.close();
45+
}
46+
}
4047
}
4148
});
4249
});

resources/views/components/search-table.blade.php

Lines changed: 7 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -23,70 +23,20 @@
2323
$filter = [];
2424
$filter_values = [];
2525
26-
foreach($fields as $key => $field){
27-
28-
if(!empty($field["filter"])){
29-
if(!empty($advanced[$key])){
30-
if(($field["advanced-type"] ?? null) == "date-range"){
31-
$dates = explode(" - ", $advanced[$key]);
32-
33-
$filter[] = ($field["custom-filter"] ?? $key)." BETWEEN ? AND ?";
34-
$advanced_values[] = Help::convert_date($dates[0]);
35-
$advanced_values[] = Help::convert_date($dates[1] ?? $dates[0]);
36-
}
37-
else if(($field["advanced-type"] ?? null) == "in-array"){
38-
$multi_filter = [];
39-
40-
foreach($advanced[$key] as $value){
41-
$multi_filter[] = "CONVERT(".($field["custom-filter"] ?? $key)." using 'utf8') LIKE '%".$value."%'";
42-
}
43-
44-
$filter[] = "(".implode(" AND ", $multi_filter).")";
45-
}
46-
else if(($field["advanced-type"] ?? null) == "like"){
47-
$filter[] = "CONVERT(".($field["custom-filter"] ?? $key)." using 'utf8') LIKE '%".$advanced[$key]."%'";
48-
}
49-
else{
50-
$multi_filter = [];
51-
52-
foreach($advanced[$key] as $value){
53-
$multi_filter[] = "CONVERT(".($field["custom-filter"] ?? $key)." using 'utf8') = ?";
54-
$advanced_values[] = $value;
55-
}
56-
57-
$filter[] = "(".implode(" OR ", $multi_filter).")";
58-
}
59-
}
60-
else if(Help::empty_dictionary($advanced)){
61-
$filter[] = "CONVERT(".($field["custom-filter"] ?? $key)." using 'utf8') LIKE ?";
62-
$filter_values[] = "%".$query."%";
63-
}
64-
}
65-
66-
if(!empty($field["sort"])){
67-
$model_sort[] = ($field["custom-filter"] ?? $key)." ".$field["sort"];
68-
}
69-
}
26+
$search = $model::filter([
27+
"query" => $query,
28+
"advanced_search" => $advanced,
29+
], true);
7030
71-
// Perform model search
72-
$search = !empty($filter) ? $model::whereRaw("(".implode(Help::empty_dictionary($advanced) ? " OR " : " AND ", $filter).")", !Help::empty_dictionary($advanced) ? $advanced_values : $filter_values) : $model::query();
31+
// Clone search for count rows
32+
$count = clone($search);
7333
7434
if(!empty($advanced)){
7535
// dd($advanced);
7636
// $search->dd();
7737
// dd(Help::empty_dictionary($advanced));
38+
// dd($search->dd());
7839
}
79-
80-
// Check model filter
81-
foreach($modelfilter as $key => $value){
82-
$search = $search->whereRaw("CONVERT(".($fields[$key]["custom-filter"] ?? $fields[$key]["key"] ?? $key)." using 'utf8') = ?", $value);
83-
}
84-
85-
// Clone search for count rows
86-
$count = clone($search);
87-
88-
// Apply order by
89-
$search->orderByRaw(implode(",", $model_sort));
9040
@endphp
9141
{{-- <div class="row">
9242
<div class="col-md-12">

routes/requests.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
Route::post('add-url-modal', [ShortController::class, 'add_url_modal'])->name('short.add-url-modal');
2525
Route::post('add-url', [ShortController::class, 'add_url'])->name('short.add-url');
2626
Route::put('upload-csv', [ShortController::class, 'upload_csv'])->name('short.upload-csv');
27+
Route::get('multiple-download', [ShortController::class, 'multiple_download'])->name('short.multiple-download');
2728

2829
Route::prefix("{short}")->group(function(){
2930
Route::put('update', [ShortController::class, 'update'])->name('short.update');

0 commit comments

Comments
 (0)