1 | <?php |
||||
2 | /** |
||||
3 | * This file is part of Part-DB (https://github.com/Part-DB/Part-DB-symfony). |
||||
4 | * |
||||
5 | * Copyright (C) 2019 - 2022 Jan Böhmer (https://github.com/jbtronics) |
||||
6 | * |
||||
7 | * This program is free software: you can redistribute it and/or modify |
||||
8 | * it under the terms of the GNU Affero General Public License as published |
||||
9 | * by the Free Software Foundation, either version 3 of the License, or |
||||
10 | * (at your option) any later version. |
||||
11 | * |
||||
12 | * This program is distributed in the hope that it will be useful, |
||||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
15 | * GNU Affero General Public License for more details. |
||||
16 | * |
||||
17 | * You should have received a copy of the GNU Affero General Public License |
||||
18 | * along with this program. If not, see <https://www.gnu.org/licenses/>. |
||||
19 | */ |
||||
20 | |||||
21 | declare(strict_types=1); |
||||
22 | |||||
23 | namespace App\DataTables; |
||||
24 | |||||
25 | use App\DataTables\Column\LocaleDateTimeColumn; |
||||
26 | use App\DataTables\Column\PrettyBoolColumn; |
||||
27 | use App\DataTables\Column\RowClassColumn; |
||||
28 | use App\DataTables\Filters\AttachmentFilter; |
||||
29 | use App\Entity\Attachments\Attachment; |
||||
30 | use App\Entity\LogSystem\AbstractLogEntry; |
||||
31 | use App\Services\Attachments\AttachmentManager; |
||||
32 | use App\Services\Attachments\AttachmentURLGenerator; |
||||
33 | use App\Services\ElementTypeNameGenerator; |
||||
34 | use App\Services\EntityURLGenerator; |
||||
35 | use Doctrine\ORM\QueryBuilder; |
||||
36 | use Omines\DataTablesBundle\Adapter\Doctrine\ORM\SearchCriteriaProvider; |
||||
37 | use Omines\DataTablesBundle\Adapter\Doctrine\ORMAdapter; |
||||
38 | use Omines\DataTablesBundle\Column\TextColumn; |
||||
39 | use Omines\DataTablesBundle\DataTable; |
||||
40 | use Omines\DataTablesBundle\DataTableTypeInterface; |
||||
41 | use Symfony\Contracts\Translation\TranslatorInterface; |
||||
42 | |||||
43 | final class AttachmentDataTable implements DataTableTypeInterface |
||||
44 | { |
||||
45 | private TranslatorInterface $translator; |
||||
46 | private EntityURLGenerator $entityURLGenerator; |
||||
47 | private AttachmentManager $attachmentHelper; |
||||
48 | private ElementTypeNameGenerator $elementTypeNameGenerator; |
||||
49 | private AttachmentURLGenerator $attachmentURLGenerator; |
||||
50 | |||||
51 | public function __construct(TranslatorInterface $translator, EntityURLGenerator $entityURLGenerator, |
||||
52 | AttachmentManager $attachmentHelper, AttachmentURLGenerator $attachmentURLGenerator, |
||||
53 | ElementTypeNameGenerator $elementTypeNameGenerator) |
||||
54 | { |
||||
55 | $this->translator = $translator; |
||||
56 | $this->entityURLGenerator = $entityURLGenerator; |
||||
57 | $this->attachmentHelper = $attachmentHelper; |
||||
58 | $this->elementTypeNameGenerator = $elementTypeNameGenerator; |
||||
59 | $this->attachmentURLGenerator = $attachmentURLGenerator; |
||||
60 | } |
||||
61 | |||||
62 | public function configure(DataTable $dataTable, array $options): void |
||||
63 | { |
||||
64 | $dataTable->add('dont_matter', RowClassColumn::class, [ |
||||
65 | 'render' => function ($value, Attachment $context) { |
||||
66 | //Mark attachments with missing files yellow |
||||
67 | if(!$this->attachmentHelper->isFileExisting($context)){ |
||||
68 | return 'table-warning'; |
||||
69 | } |
||||
70 | |||||
71 | return ''; //Default coloring otherwise |
||||
72 | }, |
||||
73 | ]); |
||||
74 | |||||
75 | $dataTable->add('picture', TextColumn::class, [ |
||||
76 | 'label' => '', |
||||
77 | 'className' => 'no-colvis', |
||||
78 | 'render' => function ($value, Attachment $context) { |
||||
79 | if ($context->isPicture() |
||||
80 | && !$context->isExternal() |
||||
81 | && $this->attachmentHelper->isFileExisting($context)) { |
||||
82 | $title = htmlspecialchars($context->getName()); |
||||
83 | if ($context->getFilename()) { |
||||
84 | $title .= ' ('.htmlspecialchars($context->getFilename()).')'; |
||||
85 | } |
||||
86 | |||||
87 | return sprintf( |
||||
88 | '<img alt="%s" src="%s" data-thumbnail="%s" class="%s" data-title="%s" data-controller="elements--hoverpic">', |
||||
89 | 'Part image', |
||||
90 | $this->attachmentURLGenerator->getThumbnailURL($context), |
||||
91 | $this->attachmentURLGenerator->getThumbnailURL($context, 'thumbnail_md'), |
||||
92 | 'img-fluid hoverpic', |
||||
93 | $title |
||||
94 | ); |
||||
95 | } |
||||
96 | |||||
97 | return ''; |
||||
98 | }, |
||||
99 | ]); |
||||
100 | |||||
101 | $dataTable->add('name', TextColumn::class, [ |
||||
102 | 'label' => 'attachment.edit.name', |
||||
103 | 'render' => function ($value, Attachment $context) { |
||||
104 | //Link to external source |
||||
105 | if ($context->isExternal()) { |
||||
106 | return sprintf( |
||||
107 | '<a href="%s" class="link-external">%s</a>', |
||||
108 | htmlspecialchars($context->getURL()), |
||||
0 ignored issues
–
show
Bug
introduced
by
![]() |
|||||
109 | htmlspecialchars($value) |
||||
110 | ); |
||||
111 | } |
||||
112 | |||||
113 | if ($this->attachmentHelper->isFileExisting($context)) { |
||||
114 | return sprintf( |
||||
115 | '<a href="%s" target="_blank" data-no-ajax>%s</a>', |
||||
116 | $this->entityURLGenerator->viewURL($context), |
||||
117 | htmlspecialchars($value) |
||||
118 | ); |
||||
119 | } |
||||
120 | |||||
121 | return $value; |
||||
122 | }, |
||||
123 | ]); |
||||
124 | |||||
125 | $dataTable->add('attachment_type', TextColumn::class, [ |
||||
126 | 'label' => 'attachment.table.type', |
||||
127 | 'field' => 'attachment_type.name', |
||||
128 | 'render' => function ($value, Attachment $context) { |
||||
129 | return sprintf( |
||||
130 | '<a href="%s">%s</a>', |
||||
131 | $this->entityURLGenerator->editURL($context->getAttachmentType()), |
||||
132 | htmlspecialchars($value) |
||||
133 | ); |
||||
134 | }, |
||||
135 | ]); |
||||
136 | |||||
137 | $dataTable->add('element', TextColumn::class, [ |
||||
138 | 'label' => 'attachment.table.element', |
||||
139 | //'propertyPath' => 'element.name', |
||||
140 | 'render' => function ($value, Attachment $context) { |
||||
141 | return sprintf( |
||||
142 | '<a href="%s">%s</a>', |
||||
143 | $this->entityURLGenerator->infoURL($context->getElement()), |
||||
0 ignored issues
–
show
It seems like
$context->getElement() can also be of type null ; however, parameter $entity of App\Services\EntityURLGenerator::infoURL() does only seem to accept App\Entity\Base\AbstractDBElement , maybe add an additional type check?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||
144 | $this->elementTypeNameGenerator->getTypeNameCombination($context->getElement(), true) |
||||
0 ignored issues
–
show
It seems like
$context->getElement() can also be of type null ; however, parameter $entity of App\Services\ElementType...etTypeNameCombination() does only seem to accept App\Entity\Contracts\NamedElementInterface , maybe add an additional type check?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||
145 | ); |
||||
146 | }, |
||||
147 | ]); |
||||
148 | |||||
149 | $dataTable->add('filename', TextColumn::class, [ |
||||
150 | 'label' => $this->translator->trans('attachment.table.filename'), |
||||
151 | 'propertyPath' => 'filename', |
||||
152 | ]); |
||||
153 | |||||
154 | $dataTable->add('filesize', TextColumn::class, [ |
||||
155 | 'label' => $this->translator->trans('attachment.table.filesize'), |
||||
156 | 'render' => function ($value, Attachment $context) { |
||||
157 | if ($context->isExternal()) { |
||||
158 | return sprintf( |
||||
159 | '<span class="badge bg-primary"> |
||||
160 | <i class="fas fa-globe fa-fw"></i>%s |
||||
161 | </span>', |
||||
162 | $this->translator->trans('attachment.external') |
||||
163 | ); |
||||
164 | } |
||||
165 | |||||
166 | if ($this->attachmentHelper->isFileExisting($context)) { |
||||
167 | return $this->attachmentHelper->getHumanFileSize($context); |
||||
168 | } |
||||
169 | |||||
170 | return sprintf( |
||||
171 | '<span class="badge bg-warning"> |
||||
172 | <i class="fas fa-exclamation-circle fa-fw"></i>%s |
||||
173 | </span>', |
||||
174 | $this->translator->trans('attachment.file_not_found') |
||||
175 | ); |
||||
176 | }, |
||||
177 | ]); |
||||
178 | |||||
179 | $dataTable |
||||
180 | ->add('addedDate', LocaleDateTimeColumn::class, [ |
||||
181 | 'label' => 'part.table.addedDate', |
||||
182 | 'visible' => false, |
||||
183 | ]) |
||||
184 | ->add('lastModified', LocaleDateTimeColumn::class, [ |
||||
185 | 'label' => 'part.table.lastModified', |
||||
186 | 'visible' => false, |
||||
187 | ]); |
||||
188 | |||||
189 | $dataTable->add('show_in_table', PrettyBoolColumn::class, [ |
||||
190 | 'label' => 'attachment.edit.show_in_table', |
||||
191 | 'visible' => false, |
||||
192 | ]); |
||||
193 | |||||
194 | $dataTable->add('isPicture', PrettyBoolColumn::class, [ |
||||
195 | 'label' => 'attachment.edit.isPicture', |
||||
196 | 'visible' => false, |
||||
197 | 'propertyPath' => 'picture', |
||||
198 | ]); |
||||
199 | |||||
200 | $dataTable->add('is3DModel', PrettyBoolColumn::class, [ |
||||
201 | 'label' => 'attachment.edit.is3DModel', |
||||
202 | 'visible' => false, |
||||
203 | 'propertyPath' => '3dmodel', |
||||
204 | ]); |
||||
205 | |||||
206 | $dataTable->add('isBuiltin', PrettyBoolColumn::class, [ |
||||
207 | 'label' => 'attachment.edit.isBuiltin', |
||||
208 | 'visible' => false, |
||||
209 | 'propertyPath' => 'builtin', |
||||
210 | ]); |
||||
211 | |||||
212 | $dataTable->createAdapter(ORMAdapter::class, [ |
||||
213 | 'entity' => Attachment::class, |
||||
214 | 'query' => function (QueryBuilder $builder): void { |
||||
215 | $this->getQuery($builder); |
||||
216 | }, |
||||
217 | 'criteria' => [ |
||||
218 | function (QueryBuilder $builder) use ($options): void { |
||||
219 | $this->buildCriteria($builder, $options); |
||||
220 | }, |
||||
221 | new SearchCriteriaProvider(), |
||||
222 | ], |
||||
223 | ]); |
||||
224 | } |
||||
225 | |||||
226 | private function getQuery(QueryBuilder $builder): void |
||||
227 | { |
||||
228 | $builder->select('attachment') |
||||
229 | ->addSelect('attachment_type') |
||||
230 | //->addSelect('element') |
||||
231 | ->from(Attachment::class, 'attachment') |
||||
232 | ->leftJoin('attachment.attachment_type', 'attachment_type'); |
||||
233 | //->leftJoin('attachment.element', 'element'); |
||||
234 | } |
||||
235 | |||||
236 | private function buildCriteria(QueryBuilder $builder, array $options): void |
||||
237 | { |
||||
238 | //We do the most stuff here in the filter class |
||||
239 | if (isset($options['filter'])) { |
||||
240 | if(!$options['filter'] instanceof AttachmentFilter) { |
||||
241 | throw new \Exception('filter must be an instance of AttachmentFilter!'); |
||||
242 | } |
||||
243 | |||||
244 | $filter = $options['filter']; |
||||
245 | $filter->apply($builder); |
||||
246 | } |
||||
247 | |||||
248 | } |
||||
249 | } |
||||
250 |