<?php
namespace App\Controller\Admin;
use App\Entity\Article;
use App\Service\Article\ArticleService;
use App\Service\Center\CenterService;
use App\Service\Spreadsheet\SpreadsheetService;
use App\Service\User\UserService;
use App\Service\Warehouse\WarehouseService;
use App\Util\UserRole;
use Doctrine\ORM\EntityManagerInterface;
use EasyCorp\Bundle\EasyAdminBundle\Config\Action;
use EasyCorp\Bundle\EasyAdminBundle\Config\Actions;
use EasyCorp\Bundle\EasyAdminBundle\Config\Crud;
use EasyCorp\Bundle\EasyAdminBundle\Config\Filters;
use EasyCorp\Bundle\EasyAdminBundle\Context\AdminContext;
use EasyCorp\Bundle\EasyAdminBundle\Controller\AbstractCrudController;
use EasyCorp\Bundle\EasyAdminBundle\Dto\BatchActionDto;
use EasyCorp\Bundle\EasyAdminBundle\Field\AssociationField;
use EasyCorp\Bundle\EasyAdminBundle\Field\BooleanField;
use EasyCorp\Bundle\EasyAdminBundle\Field\IntegerField;
use EasyCorp\Bundle\EasyAdminBundle\Field\TextareaField;
use EasyCorp\Bundle\EasyAdminBundle\Field\TextField;
use EasyCorp\Bundle\EasyAdminBundle\Filter\BooleanFilter;
use EasyCorp\Bundle\EasyAdminBundle\Filter\EntityFilter;
use EasyCorp\Bundle\EasyAdminBundle\Filter\TextFilter;
use EasyCorp\Bundle\EasyAdminBundle\Router\AdminUrlGenerator;
use PhpOffice\PhpSpreadsheet\Writer\IWriter;
use Symfony\Component\HttpFoundation\StreamedResponse;
use Symfony\Contracts\Translation\TranslatorInterface;
abstract class ArticleBaseCrudController extends AbstractCrudController
{
use UserRole;
const LENGHTSHORTNAME = 90;
private const CONTENT_TYPE = 'application/vnd.ms-excel';
private const WRITER_TYPE = 'Xlsx';
private const FILENAME_ARTICLES = 'articles.xlsx';
private const HEADERS_ARTICLES =
[
'code' => 'Referencia interna',
'name' => 'Nombre completo',
'warehouse' => 'Almacén central',
'active' => 'Activo',
];
private $translator;
private $warehouseService;
private $adminUrlGenerator;
private $centerService;
private $articleService;
private $userService;
private SpreadsheetService $spreadsheetService;
public function __construct(
TranslatorInterface $translator,
AdminUrlGenerator $adminUrlGenerator,
WarehouseService $warehouseService,
CenterService $centerService,
ArticleService $articleService,
UserService $userService,
SpreadsheetService $spreadsheetService
) {
$this->translator = $translator;
$this->adminUrlGenerator = $adminUrlGenerator;
$this->warehouseService = $warehouseService;
$this->centerService = $centerService;
$this->articleService = $articleService;
$this->userService = $userService;
$this->spreadsheetService = $spreadsheetService;
}
public static function getEntityFqcn(): string
{
return Article::class;
}
public function configureCrud(Crud $crud): Crud
{
return $crud
->setPageTitle(Crud::PAGE_INDEX, $this->translator->trans('pages.article.index.title'))
->setPageTitle(Crud::PAGE_NEW, $this->translator->trans('pages.article.new.title'))
/* ->setPageTitle(Crud::PAGE_EDIT, fn (Article $article) => $this->translator->trans('pages.article.edit.title',
[
'article' => $article->getShortName(),
]))
->setPageTitle(Crud::PAGE_DETAIL, fn (Article $article) => $this->translator->trans('pages.article.view.title',
[
'article' => $article->getShortName(),
]))*/
->setEntityLabelInSingular($this->translator->trans('pages.article.common.article'))
->setSearchFields(['code', 'completeName', 'warehouse.name', 'active'])
->setDefaultSort(['id' => 'ASC'])
->setPaginatorPageSize(250)
->overrideTemplate('crud/index', 'admin/article/index.html.twig')
;
}
public function configureActions(Actions $actions): Actions
{
//Permissions
$actions
->setPermission(Action::DETAIL, $this->getUser()->getRoles()[0])
->setPermission(Action::EDIT, $this->roleWarehouse)
->setPermission(Action::NEW, $this->roleWarehouse)
->setPermission(Action::DELETE, $this->roleSuperAdmin)
->setPermission(Action::BATCH_DELETE, $this->roleSuperAdmin);
//Create custom Actions
$exchangeArticleAction =
Action::new('exchange_article', false, 'fas fa-exchange-alt')
->setHtmlAttributes(['title' => $this->translator->trans('pages.article.common.internal.exchange')])
->linkToCrudAction('exchangeArticleAction')
->displayIf(
function ($entity) {
return $this->roleHasPermission($entity);
}
);
$listLocations =
Action::new('list_locations', false, 'fas fa-map-marker-alt')
->linkToCrudAction('listLocationAction')
->setHtmlAttributes(['title' => $this->translator->trans('pages.article.common.internal.location')]);
$printAllArticleLocationsCustomAction =
Action::new('print_all_article_locations', false, 'fas fa-print')
->linkToCrudAction('printLabelAction')
->setHtmlAttributes(['title' => $this->translator->trans('pages.article.common.internal.print')]);
$exportExcelCustomBatchAction = Action::new('export_excel_batch_action', false)
->linkToCrudAction('exportExcelBatchAction')
->setIcon('fa fa-file-excel');
//Set actions
$actions
->add(Crud::PAGE_INDEX, $exchangeArticleAction)
->add(Crud::PAGE_INDEX, $printAllArticleLocationsCustomAction)
->add(Crud::PAGE_INDEX, $listLocations)
->add(Crud::PAGE_INDEX, Action::DETAIL)
->addBatchAction($exportExcelCustomBatchAction)
->update(Crud::PAGE_INDEX, Action::DETAIL, function (Action $action) {
return $action->setIcon('fas fa-eye')->setLabel(false)
->setHtmlAttributes(['title' => $this->translator->trans('pages.article.common.internal.detail')])
;
})
->update(Crud::PAGE_INDEX, Action::EDIT, function (Action $action) {
return $action->setIcon('fas fa-edit')->setLabel(false)
->setHtmlAttributes(['title' => $this->translator->trans('pages.article.common.internal.edit')])
->displayIf(
function ($entity) {
return $this->roleHasPermission($entity);
}
);
})
->update(Crud::PAGE_INDEX, Action::DELETE, function (Action $action) {
return $action->setIcon('fas fa-trash-alt')->setLabel(false);
})
->update(Crud::PAGE_INDEX, Action::BATCH_DELETE, function (Action $action) {
return $action->setIcon('fas fa-trash-alt')->setLabel(false);
})
;
return $actions;
}
//This function will never run. Override in admin/level/index.html.twig
public function exchangeArticleAction(AdminContext $context)
{
$url = $this->adminUrlGenerator
->setController(ArticleCrudController::class)
->setAction(Action::INDEX)
->generateUrl();
return $this->redirect($url);
}
//This function will never run. Override in admin/location/index.html.twig
public function printLabelAction(AdminContext $context)
{
$url = $this->adminUrlGenerator
->setController(ArticleCrudController::class)
->setAction(Action::INDEX)
->generateUrl();
return $this->redirect($url);
}
public function configureFilters(Filters $filters): Filters
{
return $filters
->add(TextFilter::new('code', $this->translator->trans('pages.article.index.filters.code')))
->add(TextFilter::new('completeName', $this->translator->trans('pages.article.index.filters.completeName')))
->add(EntityFilter::new('warehouse', $this->translator->trans('pages.article.index.filters.warehouse')))
->add(BooleanFilter::new('active', $this->translator->trans('pages.article.index.filters.active')))
;
}
public function configureFields(string $pageName): iterable
{
$fields = [];
$code = TextField::new('code', $this->translator->trans('pages.article.common.code'))
->setMaxLength(255)->setFormTypeOption('attr', ['maxlength' => 255]);
$warehouse = AssociationField::new('warehouse', $this->translator->trans('pages.article.common.warehouse'));
$active = BooleanField::new('active', $this->translator->trans('pages.article.common.active'));
if (Crud::PAGE_INDEX === $pageName) {
$fields[] = $code;
$fields[] = TextField::new('completeName', $this->translator->trans('pages.article.common.completeName'))
->setMaxLength(255);
$fields[] = $warehouse;
$fields[] = $active->setFormTypeOption('disabled', 'disabled');
} elseif (Crud::PAGE_NEW === $pageName || Crud::PAGE_EDIT === $pageName || Crud::PAGE_DETAIL === $pageName) {
$fields[] = $code->setRequired(true);
$fields[] = TextareaField::new('completeName', $this->translator->trans('pages.article.common.completeName'))
->setRequired(true)->setMaxLength(255)->setFormTypeOption('attr', ['maxlength' => 255]);
$fields[] = TextField::new('shortName', $this->translator->trans('pages.article.common.shortName'))
->setRequired(false)->setMaxLength(self::LENGHTSHORTNAME)->setFormTypeOption('attr', ['maxlength' => self::LENGHTSHORTNAME])
->setHelp($this->translator->trans('pages.article.common.help_shortName'));
$fields[] = $warehouse->setRequired(true)->renderAsNativeWidget(true)
->setFormTypeOption(
'query_builder', function () {
return $this->warehouseService->getWarehousesByUser($this->getUser());
});
$fields[] = IntegerField::new('expirationPeriod', $this->translator->trans('pages.article.common.expirationPeriod'))
->setRequired(false)
->setHelp($this->translator->trans('pages.article.common.help_expirationPeriod'));
$fields[] = IntegerField::new('packingQuantity', $this->translator->trans('pages.article.common.packingQuantity'))
->setRequired(false);
// $fields[] = TextField::new('measurementUnit', $this->translator->trans('pages.article.common.measurementUnit'));
$fields[] = TextareaField::new('comments', $this->translator->trans('pages.article.common.comments'))
->setRequired(false)->setMaxLength(255)->setFormTypeOption('attr', ['maxlength' => 255]);
$fields[] = $active;
}
return $fields;
}
public function createEntity(string $entityFqcn)
{
return parent::createEntity($entityFqcn)
->setMeasurementUnit($this->articleService->getMeasurementUnit());
}
public function index(AdminContext $context)
{
$context->getAssets()->addJsFile('js/article/article-index.js');
$context->getAssets()->addCssFile('css/exchange/article-index.css');
$context->getAssets()->addJsFile('js/common/modal-print.js');
$context->getAssets()->addCssFile('css/common/modal-print.css');
return parent::index($context);
}
public function persistEntity(EntityManagerInterface $entityManager, $entityInstance): void
{
$this->setShortNameArticle($entityInstance);
parent::persistEntity($entityManager, $entityInstance);
}
public function updateEntity(EntityManagerInterface $entityManager, $entityInstance): void
{
$this->setShortNameArticle($entityInstance);
parent::updateEntity($entityManager, $entityInstance);
}
public function deleteEntity(EntityManagerInterface $entityManager, $entityInstance): void
{
if (count($entityInstance->getPacts())) {
$this->addFlash(
'danger',
$this->translator->trans('pages.article.common.flashMessage.errorDeletePact')
);
} elseif (count($entityInstance->getLocations())) {
$this->addFlash(
'danger',
$this->translator->trans('pages.article.common.flashMessage.errorDeleteLocation')
);
} else {
parent::deleteEntity($entityManager, $entityInstance);
}
}
public function listLocationAction(AdminContext $context)
{
$url = $this->adminUrlGenerator
->setController(LocationCrudController::class)
->setAction(Action::INDEX)
->setEntityId(null)
->set('articleId', $context->getEntity()->getInstance()->getId())
->generateUrl();
return $this->redirect($url);
}
public function exportExcelBatchAction(BatchActionDto $batchActionDto)
{
$articles = [];
foreach ($batchActionDto->getEntityIds() as $id) {
$articles[] = $this->articleService->getExportArticleById($id);
}
array_unshift($articles, self::HEADERS_ARTICLES);
$writer = $this->spreadsheetService->createWriter($articles, self::WRITER_TYPE);
return $this->generateStreamedResponse($writer, self::FILENAME_ARTICLES, self::CONTENT_TYPE);
}
private function generateStreamedResponse(IWriter $writer, string $fileName, string $contentType): StreamedResponse
{
$response = new StreamedResponse(
function () use ($writer) {
$writer->save('php://output');
}
);
$response->headers->set('Content-Type', $contentType);
$response->headers->set('Content-Disposition', 'attachment;filename="'.$fileName.'"');
$response->headers->set('Cache-Control', 'max-age=0');
return $response;
}
private function setShortNameArticle($entityInstance): void
{
if (!$entityInstance->getShortName()) {
$entityInstance->setShortName(substr($entityInstance->getCompleteName(), 0, self::LENGHTSHORTNAME));
}
}
private function roleHasPermission(Article $entity)
{
if (
in_array($this->roleWarehouse, $this->getUser()->getRoles()) &&
!$this->userService->checkIfHasWarehouse($entity->getWarehouse()
)
) {
return false;
}
if (
in_array($this->roleAdmin, $this->getUser()->getRoles()) &&
!$this->userService->checkIfHasWarehouse($entity->getWarehouse()
)
) {
return false;
}
if (
in_array($this->roleService, $this->getUser()->getRoles())
) {
return false;
}
return true;
}
}