. */ namespace App\DataTables; use App\DataTables\Column\EntityColumn; use App\DataTables\Column\LocaleDateTimeColumn; use App\DataTables\Column\MarkdownColumn; use App\DataTables\Column\SelectColumn; use App\DataTables\Helpers\PartDataTableHelper; use App\Entity\Attachments\Attachment; use App\Entity\Parts\Part; use App\Entity\ProjectSystem\ProjectBOMEntry; use App\Services\EntityURLGenerator; use App\Services\Formatters\AmountFormatter; use Doctrine\ORM\QueryBuilder; use Omines\DataTablesBundle\Adapter\Doctrine\ORM\SearchCriteriaProvider; use Omines\DataTablesBundle\Adapter\Doctrine\ORMAdapter; use Omines\DataTablesBundle\Column\TextColumn; use Omines\DataTablesBundle\DataTable; use Omines\DataTablesBundle\DataTableTypeInterface; use Symfony\Contracts\Translation\TranslatorInterface; class ProjectBomEntriesDataTable implements DataTableTypeInterface { protected TranslatorInterface $translator; protected PartDataTableHelper $partDataTableHelper; protected EntityURLGenerator $entityURLGenerator; protected AmountFormatter $amountFormatter; public function __construct(TranslatorInterface $translator, PartDataTableHelper $partDataTableHelper, EntityURLGenerator $entityURLGenerator, AmountFormatter $amountFormatter) { $this->translator = $translator; $this->partDataTableHelper = $partDataTableHelper; $this->entityURLGenerator = $entityURLGenerator; $this->amountFormatter = $amountFormatter; } public function configure(DataTable $dataTable, array $options) { $dataTable //->add('select', SelectColumn::class) ->add('picture', TextColumn::class, [ 'label' => '', 'className' => 'no-colvis', 'render' => function ($value, ProjectBOMEntry $context) { if($context->getPart() === null) { return ''; } return $this->partDataTableHelper->renderPicture($context->getPart()); }, ]) ->add('id', TextColumn::class, [ 'label' => $this->translator->trans('part.table.id'), 'visible' => false, ]) ->add('quantity', TextColumn::class, [ 'label' => $this->translator->trans('project.bom.quantity'), 'className' => 'text-center', 'render' => function ($value, ProjectBOMEntry $context) { //If we have a non-part entry, only show the rounded quantity if ($context->getPart() === null) { return round($context->getQuantity()); } //Otherwise use the unit of the part to format the quantity return htmlspecialchars($this->amountFormatter->format($context->getQuantity(), $context->getPart()->getPartUnit())); }, ]) ->add('name', TextColumn::class, [ 'label' => $this->translator->trans('part.table.name'), 'orderable' => false, 'render' => function ($value, ProjectBOMEntry $context) { if($context->getPart() === null) { return htmlspecialchars($context->getName()); } if($context->getPart() !== null) { $tmp = $this->partDataTableHelper->renderName($context->getPart()); if(!empty($context->getName())) { $tmp .= '
'.htmlspecialchars($context->getName()).''; } return $tmp; } throw new \Exception('This should never happen!'); }, ]) ->add('description', MarkdownColumn::class, [ 'label' => $this->translator->trans('part.table.description'), 'data' => function (ProjectBOMEntry $context) { if($context->getPart() !== null) { return $context->getPart()->getDescription(); } //For non-part BOM entries show the comment field return $context->getComment(); }, ]) ->add('category', EntityColumn::class, [ 'label' => $this->translator->trans('part.table.category'), 'property' => 'part.category', ]) ->add('footprint', EntityColumn::class, [ 'property' => 'part.footprint', 'label' => $this->translator->trans('part.table.footprint'), ]) ->add('manufacturer', EntityColumn::class, [ 'property' => 'part.manufacturer', 'label' => $this->translator->trans('part.table.manufacturer'), ]) ->add('mountnames', TextColumn::class, [ 'label' => 'project.bom.mountnames', 'render' => function ($value, ProjectBOMEntry $context) { $html = ''; foreach (explode(',', $context->getMountnames()) as $mountname) { $html .= sprintf('%s ', htmlspecialchars($mountname)); } return $html; }, ]) ->add('addedDate', LocaleDateTimeColumn::class, [ 'label' => $this->translator->trans('part.table.addedDate'), 'visible' => false, ]) ->add('lastModified', LocaleDateTimeColumn::class, [ 'label' => $this->translator->trans('part.table.lastModified'), 'visible' => false, ]) ; $dataTable->createAdapter(ORMAdapter::class, [ 'entity' => Attachment::class, 'query' => function (QueryBuilder $builder) use ($options): void { $this->getQuery($builder, $options); }, 'criteria' => [ function (QueryBuilder $builder) use ($options): void { $this->buildCriteria($builder, $options); }, new SearchCriteriaProvider(), ], ]); } private function getQuery(QueryBuilder $builder, array $options): void { $builder->select('bom_entry') ->addSelect('part') ->from(ProjectBOMEntry::class, 'bom_entry') ->leftJoin('bom_entry.part', 'part') ->where('bom_entry.project = :project') ->setParameter('project', $options['project']) ; } private function buildCriteria(QueryBuilder $builder, array $options): void { } }