namespace Lc\AdminBundle\Controller\Admin; | namespace Lc\AdminBundle\Controller\Admin; | ||||
use App\Entity\Page; | use App\Entity\Page; | ||||
use EasyCorp\Bundle\EasyAdminBundle\Config\Action; | |||||
use EasyCorp\Bundle\EasyAdminBundle\Config\Actions; | |||||
use EasyCorp\Bundle\EasyAdminBundle\Config\Assets; | |||||
use EasyCorp\Bundle\EasyAdminBundle\Config\Crud; | use EasyCorp\Bundle\EasyAdminBundle\Config\Crud; | ||||
use EasyCorp\Bundle\EasyAdminBundle\Controller\AbstractCrudController as EaAbstractCrudController; | use EasyCorp\Bundle\EasyAdminBundle\Controller\AbstractCrudController as EaAbstractCrudController; | ||||
use EasyCorp\Bundle\EasyAdminBundle\Router\AdminUrlGenerator; | |||||
use Lc\AdminBundle\IModel\Translation\TranslatableInterface; | |||||
abstract class AbstractCrudController extends EaAbstractCrudController | abstract class AbstractCrudController extends EaAbstractCrudController | ||||
{ | { | ||||
public function configureActions(Actions $actions): Actions | |||||
{ | |||||
if (in_array(TranslatableInterface::class, class_implements($this->getEntityFqcn()))) { | |||||
$actions->update(Crud::PAGE_INDEX, Action::EDIT, function (Action $action) { | |||||
return $action->setTemplatePath('@LcAdmin/crud/action/translatable.html.twig'); | |||||
}); | |||||
} | |||||
return $actions; | |||||
} | |||||
public function configureCrud(Crud $crud): Crud | |||||
{ | |||||
return $crud | |||||
->overrideTemplates([ | |||||
'crud/edit' => '@LcAdmin/crud/edit.html.twig', | |||||
'crud/new' => '@LcAdmin/crud/new.html.twig' | |||||
]) | |||||
// don't forget to add EasyAdmin's form theme at the end of the list | |||||
// (otherwise you'll lose all the styles for the rest of form fields) | |||||
->setFormThemes(['@LcAdmin/crud/form_theme.html.twig', '@FOSCKEditor/Form/ckeditor_widget.html.twig']); | |||||
} | |||||
public function configureAssets(Assets $assets): Assets | |||||
{ | |||||
return $assets | |||||
// adds the CSS and JS assets associated to the given Webpack Encore entry | |||||
// it's equivalent to calling encore_entry_link_tags('...') and encore_entry_script_tags('...') | |||||
//->addWebpackEncoreEntry('admin-app') | |||||
// the argument of these methods is passed to the asset() Twig function | |||||
// CSS assets are added just before the closing </head> element | |||||
// and JS assets are added just before the closing </body> element | |||||
->addJsFile('bundles/lcadmin/js/utils.js'); | |||||
} | |||||
/* | /* | ||||
public function configureFields(string $pageName): iterable | public function configureFields(string $pageName): iterable | ||||
{ | { |
public function index(): Response | public function index(): Response | ||||
{ | { | ||||
return parent::index(); | |||||
return $this->render('@LcAdmin/dashboard.html.twig'); | |||||
} | } | ||||
public function configureDashboard(): Dashboard | public function configureDashboard(): Dashboard |
<?php | |||||
namespace Lc\AdminBundle\DependencyInjection; | |||||
use Symfony\Component\Config\Definition\Builder\TreeBuilder; | |||||
use Symfony\Component\Config\Definition\ConfigurationInterface; | |||||
/** | |||||
* This is the class that validates and merges configuration from your app/config files | |||||
* | |||||
* To learn more see {@link http://symfony.com/doc/current/cookbook/bundles/extension.html#cookbook-bundles-extension-config-class} | |||||
*/ | |||||
class Configuration implements ConfigurationInterface | |||||
{ | |||||
/** | |||||
* {@inheritdoc} | |||||
*/ | |||||
public function getConfigTreeBuilder() | |||||
{ | |||||
$treeBuilder = new TreeBuilder('lc_admin'); | |||||
$rootNode = $treeBuilder->getRootNode(); | |||||
$rootNode | |||||
->children() | |||||
->scalarNode('dashboardDefault')->defaultValue('App\Controller\Admin\DashboardController')->end() | |||||
->end(); | |||||
return $treeBuilder; | |||||
} | |||||
} |
use Symfony\Component\DependencyInjection\Extension\PrependExtensionInterface; | use Symfony\Component\DependencyInjection\Extension\PrependExtensionInterface; | ||||
use Symfony\Component\DependencyInjection\Loader\YamlFileLoader; | use Symfony\Component\DependencyInjection\Loader\YamlFileLoader; | ||||
class LcAdminExtension extends Extension implements PrependExtensionInterface | class LcAdminExtension extends Extension implements PrependExtensionInterface | ||||
{ | { | ||||
public function load(array $configs, ContainerBuilder $container) | public function load(array $configs, ContainerBuilder $container) | ||||
{ | { | ||||
$configuration = new Configuration(); | |||||
$config = $this->processConfiguration($configuration, $configs); | |||||
foreach ($config as $parameter => $value) | |||||
$container->setParameter(sprintf('lc_admin.%s', $parameter), $value); | |||||
$loader = new YamlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config')); | |||||
$loader->load('services.yml'); | |||||
} | } | ||||
public function prepend(ContainerBuilder $container) | public function prepend(ContainerBuilder $container) |
<?php | |||||
namespace Lc\AdminBundle\Entity\Translation; | |||||
use Doctrine\ORM\Mapping as ORM; | |||||
use Gedmo\Translatable\Entity\MappedSuperclass\AbstractTranslation; | |||||
/** | |||||
* @ORM\Table(name="lc_translations_entity", indexes={ | |||||
* @ORM\Index(name="entity_translation_idx", columns={"locale", "object_class", "field", "foreign_key"}) | |||||
* }) | |||||
* @ORM\Entity(repositoryClass="Lc\AdminBundle\Repository\BaseRepository") | |||||
*/ | |||||
class EntityTranslation extends AbstractTranslation | |||||
{ | |||||
//put your code here | |||||
} |
<?php | |||||
namespace Lc\AdminBundle\EventSubscriber\Translation; | |||||
use Doctrine\ORM\PersistentCollection; | |||||
use Doctrine\ORM\Query; | |||||
use EasyCorp\Bundle\EasyAdminBundle\Event\AfterCrudActionEvent; | |||||
use EasyCorp\Bundle\EasyAdminBundle\Event\BeforeCrudActionEvent; | |||||
use EasyCorp\Bundle\EasyAdminBundle\Event\BeforeEntityPersistedEvent; | |||||
use Gedmo\Translatable\TranslatableListener; | |||||
use Lc\AdminBundle\IModel\Translation\TranslatableInterface; | |||||
use Lc\AdminBundle\Manager\EntityManager; | |||||
use Symfony\Component\EventDispatcher\EventSubscriberInterface; | |||||
use function Symfony\Component\Translation\t; | |||||
class TranslationEasyAdminSubscriber implements EventSubscriberInterface | |||||
{ | |||||
protected $em; | |||||
public function __construct(EntityManager $entityManager) | |||||
{ | |||||
$this->em = $entityManager; | |||||
} | |||||
public static function getSubscribedEvents() | |||||
{ | |||||
return [ | |||||
BeforeCrudActionEvent::class => ['setTranslatableLocale'] | |||||
]; | |||||
} | |||||
public function setTranslatableLocale(BeforeCrudActionEvent $event) | |||||
{ | |||||
$entity = $event->getAdminContext()->getEntity()->getInstance(); | |||||
$_locale = $event->getAdminContext()->getRequest()->get('_locale'); | |||||
if($entity instanceof TranslatableInterface){ | |||||
//parcours les champs association pour détecter un champ de association qui est traduisible | |||||
foreach ($this->em->getClassMetadata(get_class($entity))->getAssociationMappings() as $associationMapping){ | |||||
if (in_array(TranslatableInterface::class, class_implements($associationMapping["targetEntity"]))){ | |||||
if($entity->__get($associationMapping['fieldName']) instanceof PersistentCollection){ | |||||
foreach ($entity->__get($associationMapping['fieldName']) as $item){ | |||||
$item->setTranslatableLocale($_locale); | |||||
$this->em->refresh($item); | |||||
} | |||||
}else{ | |||||
if($entity->__get($associationMapping['fieldName'])) { | |||||
$entity->__get($associationMapping['fieldName'])->setTranslatableLocale($_locale); | |||||
$this->em->refresh($entity->__get($associationMapping['fieldName'])); | |||||
} | |||||
} | |||||
} | |||||
} | |||||
$entity->setTranslatableLocale($_locale); | |||||
$this->em->refresh($entity); | |||||
} | |||||
} | |||||
} |
<?php | |||||
namespace Lc\AdminBundle\Field; | |||||
use EasyCorp\Bundle\EasyAdminBundle\Contracts\Field\FieldInterface; | |||||
use EasyCorp\Bundle\EasyAdminBundle\Field\FieldTrait; | |||||
use FOS\CKEditorBundle\Form\Type\CKEditorType; | |||||
/** | |||||
* @author Javier Eguiluz <javier.eguiluz@gmail.com> | |||||
*/ | |||||
final class CKEditorField implements FieldInterface | |||||
{ | |||||
use FieldTrait; | |||||
public const OPTION_NUM_OF_ROWS = 'numOfRows'; | |||||
public static function new(string $propertyName, ?string $label = null): self | |||||
{ | |||||
return (new self()) | |||||
->setProperty($propertyName) | |||||
->setLabel($label) | |||||
->setTemplateName('crud/field/text_editor') | |||||
->setFormType(CKEditorType::class) | |||||
->addCssClass('field-text_editor') | |||||
->addCssFiles('bundles/easyadmin/form-type-text-editor.css') | |||||
->addJsFiles('bundles/easyadmin/form-type-text-editor.js') | |||||
->setCustomOption(self::OPTION_NUM_OF_ROWS, null); | |||||
} | |||||
public function setNumOfRows(int $rows): self | |||||
{ | |||||
if ($rows < 1) { | |||||
throw new \InvalidArgumentException(sprintf('The argument of the "%s()" method must be 1 or higher (%d given).', __METHOD__, $rows)); | |||||
} | |||||
$this->setCustomOption(self::OPTION_NUM_OF_ROWS, $rows); | |||||
return $this; | |||||
} | |||||
} |
<?php | |||||
namespace Lc\AdminBundle\Field; | |||||
use EasyCorp\Bundle\EasyAdminBundle\Contracts\Field\FieldInterface; | |||||
use EasyCorp\Bundle\EasyAdminBundle\Field\FieldTrait; | |||||
use Lc\AdminBundle\Form\Type\FileManagerType; | |||||
use Lc\AdminBundle\Form\Type\GalleryManagerType; | |||||
use Symfony\Component\Form\Extension\Core\Type\CollectionType; | |||||
class CollectionField implements FieldInterface | |||||
{ | |||||
use FieldTrait; | |||||
public const OPTION_ALLOW_ADD = 'allowAdd'; | |||||
public const OPTION_ALLOW_DELETE = 'allowDelete'; | |||||
public const OPTION_ENTRY_IS_COMPLEX = 'entryIsComplex'; | |||||
public const OPTION_ENTRY_TYPE = 'entryType'; | |||||
public const OPTION_SHOW_ENTRY_LABEL = 'showEntryLabel'; | |||||
public static function new(string $propertyName, ?string $label = null): self | |||||
{ | |||||
return (new self()) | |||||
->setProperty($propertyName) | |||||
->setLabel($label) | |||||
->setTemplatePath('@LcAdmin/crud/field/collection.html.twig') | |||||
->setFormType(CollectionType::class) | |||||
->addCssClass('field-collection') | |||||
->addJsFiles('bundles/lcadmin/js/form-type-collection-array.js') | |||||
->setFormTypeOption('allow_add', true) | |||||
->setFormTypeOption('allow_delete', true) | |||||
->setFormTypeOption('entry_options', array('label' => false)) | |||||
->setFormTypeOption('attr', array('class' => 'field-collection-group')) | |||||
//Fixe le bug easyadmin lors de la gestion d'un champ de type array, laisser a false pour une entité | |||||
->setFormTypeOption('row_attr', array('data-reindex-key' => true)); | |||||
} | |||||
public function allowAdd(bool $allow = true): self | |||||
{ | |||||
$this->setCustomOption(self::OPTION_ALLOW_ADD, $allow); | |||||
return $this; | |||||
} | |||||
public function allowDelete(bool $allow = true): self | |||||
{ | |||||
$this->setCustomOption(self::OPTION_ALLOW_DELETE, $allow); | |||||
return $this; | |||||
} | |||||
/** | |||||
* Set this option to TRUE if the collection items are complex form types | |||||
* composed of several form fields (EasyAdmin applies a special rendering to make them look better). | |||||
*/ | |||||
public function setEntryIsComplex(bool $isComplex): self | |||||
{ | |||||
$this->setCustomOption(self::OPTION_ENTRY_IS_COMPLEX, $isComplex); | |||||
return $this; | |||||
} | |||||
public function setEntryType(string $formTypeFqcn): self | |||||
{ | |||||
$this->setCustomOption(self::OPTION_ENTRY_TYPE, $formTypeFqcn); | |||||
return $this; | |||||
} | |||||
public function showEntryLabel(bool $showLabel = true): self | |||||
{ | |||||
$this->setCustomOption(self::OPTION_SHOW_ENTRY_LABEL, $showLabel); | |||||
return $this; | |||||
} | |||||
} |
<?php | |||||
namespace Lc\AdminBundle\Field; | |||||
use EasyCorp\Bundle\EasyAdminBundle\Contracts\Field\FieldInterface; | |||||
use EasyCorp\Bundle\EasyAdminBundle\Field\FieldTrait; | |||||
use Lc\AdminBundle\Form\Type\FileManagerType; | |||||
use Symfony\Component\Form\Extension\Core\Type\TextType; | |||||
/** | |||||
* @author Javier Eguiluz <javier.eguiluz@gmail.com> | |||||
*/ | |||||
final class FileManagerField implements FieldInterface | |||||
{ | |||||
use FieldTrait; | |||||
public const OPTION_MAX_LENGTH = 'maxLength'; | |||||
public const OPTION_RENDER_AS_HTML = 'renderAsHtml'; | |||||
public static function new(string $propertyName, ?string $label = null): self | |||||
{ | |||||
return (new self()) | |||||
->setProperty($propertyName) | |||||
->setLabel($label) | |||||
->setTemplatePath('@LcAdmin/crud/field/image.html.twig') | |||||
->addJsFiles('bundles/lcadmin/js/form-type-collection.js') | |||||
->setFormType(FileManagerType::class) | |||||
->addCssClass('field-text') | |||||
->setCustomOption(self::OPTION_MAX_LENGTH, null) | |||||
->setCustomOption(self::OPTION_RENDER_AS_HTML, false); | |||||
} | |||||
public function setMaxLength(int $length): self | |||||
{ | |||||
if ($length < 1) { | |||||
throw new \InvalidArgumentException(sprintf('The argument of the "%s()" method must be 1 or higher (%d given).', __METHOD__, $length)); | |||||
} | |||||
$this->setCustomOption(self::OPTION_MAX_LENGTH, $length); | |||||
return $this; | |||||
} | |||||
public function renderAsHtml(bool $asHtml = true): self | |||||
{ | |||||
$this->setCustomOption(self::OPTION_RENDER_AS_HTML, $asHtml); | |||||
return $this; | |||||
} | |||||
} |
<?php | |||||
namespace Lc\AdminBundle\Field; | |||||
use EasyCorp\Bundle\EasyAdminBundle\Contracts\Field\FieldInterface; | |||||
use EasyCorp\Bundle\EasyAdminBundle\Field\FieldTrait; | |||||
use Lc\AdminBundle\Form\Type\FileManagerType; | |||||
use Lc\AdminBundle\Form\Type\GalleryManagerType; | |||||
use Symfony\Component\Form\Extension\Core\Type\CollectionType; | |||||
class GalleryManagerField implements FieldInterface | |||||
{ | |||||
use FieldTrait; | |||||
public const OPTION_ALLOW_ADD = 'allowAdd'; | |||||
public const OPTION_ALLOW_DELETE = 'allowDelete'; | |||||
public const OPTION_ENTRY_IS_COMPLEX = 'entryIsComplex'; | |||||
public const OPTION_ENTRY_TYPE = 'entryType'; | |||||
public const OPTION_SHOW_ENTRY_LABEL = 'showEntryLabel'; | |||||
public static function new(string $propertyName, ?string $label = null): self | |||||
{ | |||||
return (new self()) | |||||
->setProperty($propertyName) | |||||
->setLabel($label) | |||||
->setTemplatePath('@LcAdmin/crud/field/collection.html.twig') | |||||
->setFormType(CollectionType::class) | |||||
->addCssClass('field-collection') | |||||
->addJsFiles('bundles/lcadmin/js/form-type-collection.js') | |||||
->addJsFiles('bundles/lcadmin/js/form-type-file-manager.js') | |||||
->addJsFiles('bundles/lcadmin/js/jquery-ui/jquery-ui.min.js') | |||||
->setFormTypeOption('allow_add', true) | |||||
->setFormTypeOption('allow_delete', true) | |||||
->setFormTypeOption('entry_options', array('label'=> false)) | |||||
->setFormTypeOption('entry_type', FileManagerType::class) | |||||
->setFormTypeOption('attr', array('class'=> 'field-collection-group')) | |||||
->setFormTypeOption('row_attr', array('data-sortable'=> true)) | |||||
->hideOnIndex(); | |||||
//->setEntryType(FileManagerType::class); | |||||
//->setFormTypeOption('show_entry_label', false); | |||||
} | |||||
public function allowAdd(bool $allow = true): self | |||||
{ | |||||
$this->setCustomOption(self::OPTION_ALLOW_ADD, $allow); | |||||
return $this; | |||||
} | |||||
public function allowDelete(bool $allow = true): self | |||||
{ | |||||
$this->setCustomOption(self::OPTION_ALLOW_DELETE, $allow); | |||||
return $this; | |||||
} | |||||
/** | |||||
* Set this option to TRUE if the collection items are complex form types | |||||
* composed of several form fields (EasyAdmin applies a special rendering to make them look better). | |||||
*/ | |||||
public function setEntryIsComplex(bool $isComplex): self | |||||
{ | |||||
$this->setCustomOption(self::OPTION_ENTRY_IS_COMPLEX, $isComplex); | |||||
return $this; | |||||
} | |||||
public function setEntryType(string $formTypeFqcn): self | |||||
{ | |||||
$this->setCustomOption(self::OPTION_ENTRY_TYPE, $formTypeFqcn); | |||||
return $this; | |||||
} | |||||
public function showEntryLabel(bool $showLabel = true): self | |||||
{ | |||||
$this->setCustomOption(self::OPTION_SHOW_ENTRY_LABEL, $showLabel); | |||||
return $this; | |||||
} | |||||
} |
<?php | |||||
namespace Lc\AdminBundle\Form\Type; | |||||
use Lc\AdminBundle\DataTransformer\FileManagerTypeToDataTransformer; | |||||
use Lc\AdminBundle\Entity\File\File; | |||||
use Lc\AdminBundle\IModel\Cms\FileInterface; | |||||
use Lc\AdminBundle\Manager\EntityManager; | |||||
use Symfony\Component\Form\AbstractType; | |||||
use Symfony\Component\Form\DataTransformerInterface; | |||||
use Symfony\Component\Form\Extension\Core\Type\HiddenType; | |||||
use Symfony\Component\Form\Extension\Core\Type\NumberType; | |||||
use Symfony\Component\Form\Extension\Core\Type\TextType; | |||||
use Symfony\Component\Form\FormBuilderInterface; | |||||
use Symfony\Component\OptionsResolver\OptionsResolver; | |||||
class FileManagerType extends AbstractType implements DataTransformerInterface | |||||
{ | |||||
protected $em; | |||||
public function __construct(EntityManager $entityManager){ | |||||
$this->em = $entityManager; | |||||
} | |||||
public function buildForm(FormBuilderInterface $builder, array $options) | |||||
{ | |||||
$builder->add('image', HiddenType::class, array( | |||||
'block_prefix' => 'file_manager_image', | |||||
'label' => false | |||||
)); | |||||
$builder->add('legend', TextType::class, array( | |||||
'block_prefix' => 'file_manager_legend', | |||||
'attr'=> array( | |||||
"placeholder"=> 'Légende' | |||||
), | |||||
'label' => false | |||||
)); | |||||
$builder->add('position', HiddenType::class, array( | |||||
'block_prefix' => 'file_manager_position', | |||||
'empty_data'=> 0, | |||||
'required' => true, | |||||
'attr' => array( | |||||
'class' => 'field-position' | |||||
), | |||||
'label' => false | |||||
)); | |||||
} | |||||
/** | |||||
* {@inheritdoc} | |||||
*/ | |||||
public function configureOptions(OptionsResolver $resolver) | |||||
{ | |||||
$resolver->setDefaults([ | |||||
'data_class' => $this->em->getEntityName(FileInterface::class), | |||||
'compound' => true, | |||||
]); | |||||
} | |||||
/** | |||||
* {@inheritdoc} | |||||
*/ | |||||
public function getBlockPrefix() | |||||
{ | |||||
return 'file_manager'; | |||||
} | |||||
/** | |||||
* {@inheritdoc} | |||||
*/ | |||||
public function transform($data) | |||||
{ | |||||
// Model data should not be transformed | |||||
return $data; | |||||
} | |||||
/** | |||||
* {@inheritdoc} | |||||
*/ | |||||
public function reverseTransform($data) | |||||
{ | |||||
return null === $data ? '' : $data; | |||||
} | |||||
} |
namespace Lc\AdminBundle\IModel\Cms; | namespace Lc\AdminBundle\IModel\Cms; | ||||
interface ImageInterface | |||||
interface FileInterface | |||||
{ | { | ||||
} | } |
<?php | |||||
namespace Lc\AdminBundle\IModel\Translation; | |||||
interface TranslatableInterface | |||||
{ | |||||
} |
return $this; | return $this; | ||||
} | } | ||||
public function refresh(EntityInterface $entity): self | |||||
{ | |||||
$this->entityManager->refresh($entity); | |||||
return $this; | |||||
} | |||||
protected function persist(EntityInterface $entity) | protected function persist(EntityInterface $entity) | ||||
{ | { | ||||
$this->entityManager->persist($entity); | $this->entityManager->persist($entity); | ||||
} | } | ||||
public function getClassMetadata($className){ | |||||
return $this->entityManager->getClassMetadata($className); | |||||
} | |||||
public function getEntityName($className) | public function getEntityName($className) | ||||
{ | { | ||||
if (substr($className, -9) === 'Interface') { | if (substr($className, -9) === 'Interface') { |
use Lc\AdminBundle\IModel\Cms\TimestampableInterface; | use Lc\AdminBundle\IModel\Cms\TimestampableInterface; | ||||
use Lc\AdminBundle\IModel\Cms\StatusInterface; | use Lc\AdminBundle\IModel\Cms\StatusInterface; | ||||
use Doctrine\ORM\Mapping as ORM; | use Doctrine\ORM\Mapping as ORM; | ||||
use Gedmo\Mapping\Annotation as Gedmo; | |||||
use Lc\AdminBundle\IModel\EntityInterface; | use Lc\AdminBundle\IModel\EntityInterface; | ||||
/** | /** | ||||
use DevAliasTrait; | use DevAliasTrait; | ||||
/** | /** | ||||
* @Gedmo\Translatable | |||||
* @ORM\Column(type="string", length=255) | * @ORM\Column(type="string", length=255) | ||||
*/ | */ | ||||
protected $title; | protected $title; | ||||
/** | /** | ||||
* @Gedmo\Translatable | |||||
* @ORM\Column(type="text", nullable=true) | * @ORM\Column(type="text", nullable=true) | ||||
*/ | */ | ||||
protected $description; | protected $description; |
<?php | |||||
namespace Lc\AdminBundle\Model\Cms; | |||||
use Doctrine\ORM\Mapping as ORM; | |||||
use Gedmo\Mapping\Annotation as Gedmo; | |||||
use Lc\AdminBundle\IModel\Cms\BlameableInterface; | |||||
use Lc\AdminBundle\IModel\Cms\DevAliasInterface; | |||||
use Lc\AdminBundle\IModel\Cms\SortableInterface; | |||||
use Lc\AdminBundle\IModel\Cms\TimestampableInterface; | |||||
use Lc\AdminBundle\IModel\EntityInterface; | |||||
use Lc\AdminBundle\IModel\Translation\TranslatableInterface; | |||||
use Lc\AdminBundle\Model\Cms\BlameableTrait; | |||||
use Lc\AdminBundle\Model\Cms\DevAliasTrait; | |||||
use Lc\AdminBundle\Model\Cms\SortableTrait; | |||||
use Lc\AdminBundle\Model\Cms\TimestampableTrait; | |||||
use Lc\AdminBundle\Model\Translation\TranslatableTrait; | |||||
use Lc\AdminBundle\Entity\Translation\EntityTranslation; | |||||
/** | |||||
* @Gedmo\TranslationEntity (class=EntityTranslation::class) | |||||
*/ | |||||
abstract class File implements SortableInterface, BlameableInterface, TimestampableInterface, TranslatableInterface, DevAliasInterface, EntityInterface | |||||
{ | |||||
use DevAliasTrait; | |||||
use BlameableTrait; | |||||
use TimestampableTrait; | |||||
use TranslatableTrait; | |||||
use SortableTrait; | |||||
/** | |||||
* @ORM\Column(type="string", length=255, nullable=true) | |||||
*/ | |||||
protected $image; | |||||
/** | |||||
* @Gedmo\Translatable | |||||
* @ORM\Column(type="string", length=255, nullable=true) | |||||
*/ | |||||
protected $legend; | |||||
public function __toString(){ | |||||
return 'dfe'; | |||||
} | |||||
public function getImage(): ?string | |||||
{ | |||||
return $this->image; | |||||
} | |||||
public function setImage(?string $image): self | |||||
{ | |||||
$this->image = $image; | |||||
return $this; | |||||
} | |||||
public function getLegend(): ?string | |||||
{ | |||||
return $this->legend; | |||||
} | |||||
public function setLegend(?string $legend): self | |||||
{ | |||||
$this->legend = $legend; | |||||
return $this; | |||||
} | |||||
} |
<?php | |||||
namespace Lc\AdminBundle\Model\Cms; | |||||
use Doctrine\ORM\Mapping as ORM; | |||||
use Symfony\Component\HttpFoundation\File\File; | |||||
trait ImageTrait | |||||
{ | |||||
/** | |||||
* @ORM\Column(type="string", length=255, nullable=true) | |||||
*/ | |||||
protected $image; | |||||
/* /** | |||||
* @Vich\UploadableField(mapping="images", fileNameProperty="image") | |||||
* @var File | |||||
*/ | |||||
//protected $imageFile;*/ | |||||
/* | |||||
public function setImageFile(File $image = null) | |||||
{ | |||||
$this->imageFile = $image; | |||||
// VERY IMPORTANT: | |||||
// It is required that at least one field changes if you are using Doctrine, | |||||
// otherwise the event listeners won't be called and the file is lost | |||||
if ($image) { | |||||
// if 'updatedAt' is not defined in your entity, use another property | |||||
$this->updatedAt = new \DateTime('now'); | |||||
} | |||||
} | |||||
public function getImageFile() | |||||
{ | |||||
return $this->imageFile; | |||||
}*/ | |||||
public function getImage(): ?string | |||||
{ | |||||
return $this->image; | |||||
} | |||||
public function setImage(?string $image): self | |||||
{ | |||||
$this->image = $image; | |||||
return $this; | |||||
} | |||||
} |
<?php | |||||
namespace Lc\AdminBundle\Model\Translation; | |||||
use Doctrine\ORM\Mapping as ORM; | |||||
use Gedmo\Mapping\Annotation as Gedmo; | |||||
use Lc\AdminBundle\Entity\Translation\EntityTranslation; | |||||
/** | |||||
* @Gedmo\TranslationEntity(class=EntityTranslation::class) | |||||
*/ | |||||
trait TranslatableTrait | |||||
{ | |||||
/** | |||||
* Post locale | |||||
* Used locale to override Translation listener's locale | |||||
* @Gedmo\Locale | |||||
*/ | |||||
protected $locale; | |||||
/** | |||||
* @ORM\Column(type="array", nullable=true) | |||||
*/ | |||||
protected $localesEnabled = []; | |||||
public function __get($name) | |||||
{ | |||||
if(isset($this->{$name})) { | |||||
return $this->{$name}; | |||||
}else{ | |||||
return null; | |||||
} | |||||
} | |||||
public function setTranslatableLocale($locale) | |||||
{ | |||||
$this->locale = $locale; | |||||
} | |||||
public function getLocalesEnabled(): ?array | |||||
{ | |||||
return $this->localesEnabled; | |||||
} | |||||
public function setLocalesEnabled(?array $localesEnabled): self | |||||
{ | |||||
$this->localesEnabled = $localesEnabled; | |||||
return $this; | |||||
} | |||||
} |
git clone https://gitea.laclic.fr/Laclic/AdminBundle.git . | git clone https://gitea.laclic.fr/Laclic/AdminBundle.git . | ||||
``` | ``` | ||||
- Initialisation : | |||||
- Création des entités de base, créer une entité User.php et File.php, ajouter dans la configuration de doctrine les lignes suivantes | |||||
``` | |||||
doctrine: | |||||
orm: | |||||
resolve_target_entities: | |||||
Lc\AdminBundle\IModel\User\UserInterface: App\Entity\User | |||||
Lc\AdminBundle\IModel\Cms\FileInterface: App\Entity\File | |||||
#... | |||||
``` | |||||
- Instalation ckeditor | |||||
`php bin/console ckeditor:install` | |||||
`php bin/console assets:install public` | |||||
- Enjoy ! | - Enjoy ! | ||||
### Pour les projet Aquarium, Laclic, Le plat pentu (et peut être d'autres) suit cette préocédure : | ### Pour les projet Aquarium, Laclic, Le plat pentu (et peut être d'autres) suit cette préocédure : |
namespace Lc\AdminBundle\Repository; | namespace Lc\AdminBundle\Repository; | ||||
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepositoryInterface; | use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepositoryInterface; | ||||
use Doctrine\ORM\AbstractQuery; | |||||
use Doctrine\ORM\EntityManagerInterface; | use Doctrine\ORM\EntityManagerInterface; | ||||
use Doctrine\ORM\EntityRepository; | use Doctrine\ORM\EntityRepository; | ||||
use Doctrine\ORM\Query; | |||||
use Doctrine\ORM\QueryBuilder; | use Doctrine\ORM\QueryBuilder; | ||||
use Gedmo\Translatable\TranslatableListener; | |||||
use Lc\AdminBundle\IModel\Cms\StatusInterface; | use Lc\AdminBundle\IModel\Cms\StatusInterface; | ||||
abstract class BaseRepository extends EntityRepository implements ServiceEntityRepositoryInterface, BaseRepositoryInterface | abstract class BaseRepository extends EntityRepository implements ServiceEntityRepositoryInterface, BaseRepositoryInterface | ||||
{ | { | ||||
protected $merchantUtils; | |||||
protected $utils; | |||||
protected $defaultLocale; | |||||
public function setDefaultLocale($locale) | |||||
{ | |||||
$this->defaultLocale = $locale; | |||||
} | |||||
public function __construct(EntityManagerInterface $entityManager) | public function __construct(EntityManagerInterface $entityManager) | ||||
{ | { | ||||
parent::__construct($entityManager, $entityManager->getClassMetadata($this->getInterfaceClass())); | parent::__construct($entityManager, $entityManager->getClassMetadata($this->getInterfaceClass())); | ||||
} | } | ||||
public function findOneByOldUrl($url) | |||||
{ | |||||
$qb = $this->createQueryBuilder('entity') | |||||
->where('entity.oldUrls LIKE :oldUrl') | |||||
->andWhere('entity.status = 1') | |||||
->setParameter(':oldUrl', '%'.$url.'%'); | |||||
return $qb->getQuery()->getOneOrNullResult(); | |||||
} | |||||
public function findByTerm($field, $term, $limit=10){ | |||||
$qb = $this->findByMerchantQuery(); | |||||
public function getOneOrNullResult(QueryBuilder $qb, $locale = null, $hydrationMode = null) | |||||
{ | |||||
return $this->getTranslatedQuery($qb, $locale)->getOneOrNullResult($hydrationMode); | |||||
} | |||||
if($this->utils->hasFilterAssociation($field, '_')){ | |||||
$aliasRelation = $this->utils->getFilterAssociationAlias($field, '_'); | |||||
$qb->innerJoin('e.'.$aliasRelation, $aliasRelation); | |||||
$qb->select($this->utils->getFilterPropertyInit($field)); | |||||
$qb->groupBy($this->utils->getFilterPropertyInit($field)); | |||||
$qb->andWhere( | |||||
$qb->expr()->like($this->utils->getFilterPropertyInit($field), ':term')); | |||||
}else { | |||||
$qb->select('e.' . $field); | |||||
$qb->groupBy('e.' . $field); | |||||
$qb->andWhere( | |||||
$qb->expr()->like('e.' . $field, ':term')); | |||||
} | |||||
$qb->setParameter('term', '%'.$term.'%'); | |||||
$qb->setMaxResults($limit); | |||||
public function getResult(QueryBuilder $qb, $locale = null, $hydrationMode = AbstractQuery::HYDRATE_OBJECT) | |||||
{ | |||||
return $this->getTranslatedQuery($qb, $locale)->getResult($hydrationMode); | |||||
} | |||||
return $qb->getQuery()->getResult(); | |||||
public function getArrayResult(QueryBuilder $qb, $locale = null) | |||||
{ | |||||
return $this->getTranslatedQuery($qb, $locale)->getArrayResult(); | |||||
} | } | ||||
public function getSingleResult(QueryBuilder $qb, $locale = null, $hydrationMode = null) | |||||
{ | |||||
return $this->getTranslatedQuery($qb, $locale)->getSingleResult($hydrationMode); | |||||
} | |||||
public function findOneByOldUrl($url) | |||||
public function getScalarResult(QueryBuilder $qb, $locale = null) | |||||
{ | { | ||||
$qb = $this->createQueryBuilder('entity') | |||||
->where('entity.oldUrls LIKE :oldUrl') | |||||
->andWhere('entity.status = 1') | |||||
->setParameter(':oldUrl', '%'.$url.'%'); | |||||
return $this->getTranslatedQuery($qb, $locale)->getScalarResult(); | |||||
} | |||||
return $qb->getQuery()->getOneOrNullResult(); | |||||
public function getSingleScalarResult(QueryBuilder $qb, $locale = null) | |||||
{ | |||||
return $this->getTranslatedQuery($qb, $locale)->getSingleScalarResult(); | |||||
} | } | ||||
public function findByMerchantQuery() :QueryBuilder | |||||
protected function getTranslatedQuery(QueryBuilder $qb, $locale = null) | |||||
{ | { | ||||
return $this->createQueryBuilder('e') | |||||
->where('e.merchant = :currentMerchant') | |||||
->setParameter('currentMerchant', $this->merchantUtils->getMerchantCurrent()->getId()) ; | |||||
$locale = null === $locale ? $this->defaultLocale : $locale; | |||||
$query = $qb->getQuery(); | |||||
$query->setHint( | |||||
Query::HINT_CUSTOM_OUTPUT_WALKER, | |||||
'Gedmo\\Translatable\\Query\\TreeWalker\\TranslationWalker' | |||||
); | |||||
$query->setHint(TranslatableListener::HINT_TRANSLATABLE_LOCALE, $locale); | |||||
return $query; | |||||
} | } | ||||
public function findAll() | public function findAll() | ||||
{ | { | ||||
return $this->findBy(array()); | return $this->findBy(array()); |
<?php | |||||
namespace Lc\AdminBundle\Repository\Cms; | |||||
use Lc\AdminBundle\IModel\Cms\FileInterface; | |||||
use Lc\AdminBundle\Repository\BaseRepository; | |||||
/** | |||||
* @method FileInterface|null find($id, $lockMode = null, $lockVersion = null) | |||||
* @method FileInterface|null findOneBy(array $criteria, array $orderBy = null) | |||||
* @method FileInterface[] findAll() | |||||
* @method FileInterface[] findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null) | |||||
*/ | |||||
class FileRepository extends BaseRepository | |||||
{ | |||||
public function getInterfaceClass() | |||||
{ | |||||
return FileInterface::class; | |||||
} | |||||
} |
jQuery(document).ready(function () { | |||||
initCollectionWidget(); | |||||
}); | |||||
function initCollectionWidget() { | |||||
$('.field-collection[data-prototype]').each(function (i, collectionWidget) { | |||||
setCollectionWidgetSortable($(collectionWidget)); | |||||
reindexKeyCollectionWidget($(collectionWidget)); | |||||
setCollectionWidgetAdd($(collectionWidget)); | |||||
setCollectionWidgetDelete($(collectionWidget)); | |||||
}); | |||||
} | |||||
function setCollectionWidgetAdd($collectionWidget) { | |||||
if ($collectionWidget.data('allow-add')) { | |||||
$collectionWidget.find('.field-collection-add').on('click', function (e) { | |||||
// grab the prototype template | |||||
var newWidget = $collectionWidget.attr('data-prototype'); | |||||
// replace the "__name__" used in the id and name of the prototype | |||||
// with a number that's unique to your emails | |||||
// end name attribute looks like name="contact[emails][2]" | |||||
newWidget = newWidget.replace(/__name__/g, getNumItems($collectionWidget)); | |||||
// create a new list element and add it to the list | |||||
$collectionWidget.find('.form-widget-compound .field-collection-group').append(newWidget); | |||||
$collectionWidget.find('.field-collection-item:last').find('.field-position').val(getNumItems($collectionWidget)); | |||||
reindexKeyCollectionWidget($collectionWidget); | |||||
setCollectionWidgetDelete($collectionWidget); | |||||
initFileManager(); | |||||
$collectionWidget.data('num-items', $collectionWidget.data('num-items') + 1); | |||||
$collectionWidget.find('.collection-empty').hide(); | |||||
}); | |||||
} | |||||
} | |||||
function setCollectionWidgetDelete($collectionWidget) { | |||||
if ($collectionWidget.data('allow-delete')) { | |||||
$collectionWidget.find('.field-collection-delete').off('click'); | |||||
$collectionWidget.find('.field-collection-delete').on('click', function () { | |||||
$(this).parents('.form-group:first').remove(); | |||||
reindexKeyCollectionWidget($collectionWidget); | |||||
if(getNumItems($collectionWidget)==0)$collectionWidget.find('.collection-empty').show(); | |||||
}); | |||||
} | |||||
} | |||||
function getNumItems($collectionWidget) { | |||||
if ($collectionWidget.data('reindex-key')) { | |||||
return $collectionWidget.find('.field-collection-item').length; | |||||
} else { | |||||
return $collectionWidget.data('num-items'); | |||||
} | |||||
} | |||||
function reindexKeyCollectionWidget($collectionWidget) { | |||||
if ($collectionWidget.data('reindex-key')) { | |||||
$collectionWidget.find('.field-collection-item').each(function (i, item) { | |||||
$(item).find('.input[type="text"]').each(function (y, field) { | |||||
$field = $(field); | |||||
//Chanegment ID | |||||
posId = indexOfLastDigit($field.prop('id')); | |||||
idPrefix = $field.prop('id').substr(0, posId); | |||||
idSuffix = $field.prop('id').substr(posId + 1); | |||||
$field.prop('id', idPrefix + i + idSuffix); | |||||
//Chanegment Name | |||||
posName = indexOfLastDigit($field.prop('name')); | |||||
namePrefix = $field.prop('name').substr(0, posName); | |||||
nameSuffix = $field.prop('name').substr(posName + 1); | |||||
$field.prop('name', namePrefix + i + nameSuffix); | |||||
}); | |||||
}); | |||||
} | |||||
} | |||||
function setCollectionWidgetSortable($collectionWidget) { | |||||
if ($collectionWidget.data('sortable')) { | |||||
$collectionWidget.find('.field-collection-group').sortable({ | |||||
"handle" : '.lc-btn-sortable', | |||||
cancel: '' | |||||
}); | |||||
$collectionWidget.find('.field-collection-group').on("sortupdate", function (event, ui) { | |||||
$collectionWidget.find('.field-collection-group>div').each(function (index, item) { | |||||
$(item).find('.field-position').val(index); | |||||
}); | |||||
}); | |||||
} | |||||
} |
jQuery(document).ready(function () { | |||||
initFileManager(); | |||||
}); | |||||
function initFileManager() { | |||||
$('.lc-filemanager-delete').off('click'); | |||||
$('.lc-filemanager-delete').on('click', function (e) { | |||||
let $field = $(this); | |||||
$('#' + $field.data('id')).val(""); | |||||
$('#' + $field.data('id') + '_preview').prop('src',""); | |||||
}); | |||||
$('.lc-filemanager-open').off('click'); | |||||
$('.lc-filemanager-open').on('click', function (e) { | |||||
let $field = $(this); | |||||
$('#lc-filemanager-frame').off('load'); | |||||
$("#lc-filemanager-frame").on('load', function () { | |||||
$('#lc-filemanager-frame').contents().on('click', '.select', function () { | |||||
var path = $(this).attr('data-path') | |||||
$('#' + $field.data('id')).val(path); | |||||
$('#' + $field.data('id') + '_preview').prop('src',path); | |||||
$('#lc-filemanager-modal').modal('hide') | |||||
}); | |||||
}); | |||||
$("#lc-filemanager-frame").prop('src', $field.data('target')); | |||||
$('#lc-filemanager-modal').modal('show'); | |||||
}); | |||||
} |
function arrayRemove(arr, value) { return arr.filter(function(ele){ return ele != value; });} | |||||
const scratchDiv = document.createElement('div'); | |||||
function toPlainText(html) { | |||||
scratchDiv.innerHTML = html; | |||||
return scratchDiv.textContent; | |||||
} | |||||
function getDateFormatted(date, separator) { | |||||
if(date) { | |||||
var date = new Date(date); | |||||
var _d = date.getDate(), | |||||
d = _d > 9 ? _d : '0' + _d, | |||||
_m = date.getMonth() + 1, | |||||
m = _m > 9 ? _m : '0' + _m, | |||||
formatted = d + separator + m + separator + date.getFullYear(); | |||||
return formatted; | |||||
}else{ | |||||
return ''; | |||||
} | |||||
} | |||||
function log(msg) { | |||||
try { | |||||
console.log(msg); | |||||
} catch (e) { | |||||
} | |||||
} | |||||
var getUrlParameter = function getUrlParameter(sParam) { | |||||
var sPageURL = window.location.search.substring(1), | |||||
sURLVariables = sPageURL.split('&'), | |||||
sParameterName, | |||||
i; | |||||
for (i = 0; i < sURLVariables.length; i++) { | |||||
sParameterName = sURLVariables[i].split('='); | |||||
if (sParameterName[0] === sParam) { | |||||
return sParameterName[1] === undefined ? true : decodeURIComponent(sParameterName[1]); | |||||
} | |||||
} | |||||
}; | |||||
function indexOfFirstDigit(input) { | |||||
let i = 0; | |||||
for (; input[i] < '0' || input[i] > '9'; i++) ; | |||||
return i == input.length ? -1 : i; | |||||
} | |||||
function indexOfLastDigit(input) { | |||||
let i = input.length - 1; | |||||
for (; input[i] < '0' || input[i] > '9'; i--) ; | |||||
return i == input.length ? -1 : i; | |||||
} |
{# @var ea \EasyCorp\Bundle\EasyAdminBundle\Context\AdminContext #} | |||||
{# @var action \EasyCorp\Bundle\EasyAdminBundle\Dto\ActionDto #} | |||||
{# @var entity \EasyCorp\Bundle\EasyAdminBundle\Dto\EntityDto #} | |||||
{% if 'a' == action.htmlElement %} | |||||
{% for _locale in app_locales %} | |||||
<a class="{{ isIncludedInDropdown|default(false) ? 'dropdown-item' }} {{ action.cssClass }}" | |||||
href="{{ action.linkUrl }}&_locale={{ _locale }}" | |||||
{% for name, value in action.htmlAttributes %}{{ name }}="{{ value|e('html_attr') }}" {% endfor %}> | |||||
{%- if action.icon %}<i class="action-icon {{ action.icon }}"></i> {% endif -%} | |||||
{%- if action.label is not empty -%}{{ action.label }} {{ _locale }}{%- endif -%} | |||||
</a> | |||||
{% endfor %} | |||||
{% elseif 'button' == action.htmlElement %} | |||||
<button class="{{ action.cssClass }}" {% for name, value in action.htmlAttributes %}{{ name }}="{{ value|e('html_attr') }}" {% endfor %}> | |||||
<span class="btn-label"> | |||||
{%- if action.icon %}<i class="action-icon {{ action.icon }}"></i> {% endif -%} | |||||
{%- if action.label is not empty -%}{{ action.label }}{%- endif -%} | |||||
</span> | |||||
</button> | |||||
{% endif %} |
{# @var ea \EasyCorp\Bundle\EasyAdminBundle\Context\AdminContext #} | |||||
{# @var entity \EasyCorp\Bundle\EasyAdminBundle\Dto\EntityDto #} | |||||
{% extends '@EasyAdmin/crud/edit.html.twig' %} | |||||
{% block body_javascript %} | |||||
{{ parent() }} | |||||
{% include '@LcAdmin/crud/filemanager/file-manager-modal.html.twig' %} | |||||
{% endblock %} |
{# @var ea \EasyCorp\Bundle\EasyAdminBundle\Context\AdminContext #} | |||||
{# @var field \EasyCorp\Bundle\EasyAdminBundle\Dto\FieldDto #} | |||||
{# @var entity \EasyCorp\Bundle\EasyAdminBundle\Dto\EntityDto #} | |||||
{# this is a bit ugly, but Twig doesn't have a 'is numeric' test #} | |||||
{% if field.formattedValue is iterable %} | |||||
{% for item in field.formattedValue %} | |||||
<span class="badge badge-secondary">{{ item }}</span> | |||||
{% endfor %} | |||||
{% else %} | |||||
{{ field.formattedValue }} | |||||
{% endif %} |
{# @var ea \EasyCorp\Bundle\EasyAdminBundle\Context\AdminContext #} | |||||
{# @var field \EasyCorp\Bundle\EasyAdminBundle\Dto\FieldDto #} | |||||
{# @var entity \EasyCorp\Bundle\EasyAdminBundle\Dto\EntityDto #} | |||||
{# this is a bit ugly, but Twig doesn't have a 'is numeric' test #} | |||||
{% if field.formattedValue matches '/^\\d+$/' %} | |||||
<span class="badge badge-secondary">{{ field.formattedValue }}</span> | |||||
{% else %} | |||||
{{ field.formattedValue }} | |||||
{% endif %} |
{# @var ea \EasyCorp\Bundle\EasyAdminBundle\Context\AdminContext #} | |||||
{# @var field \EasyCorp\Bundle\EasyAdminBundle\Dto\FieldDto #} | |||||
{# @var entity \EasyCorp\Bundle\EasyAdminBundle\Dto\EntityDto #} | |||||
{% set html_id = 'ea-lightbox-' ~ field.uniqueId %} | |||||
<a href="#" class="ea-lightbox-thumbnail" title="{{ field.value.legend }}" data-featherlight="#{{ html_id }}" data-featherlight-close-on-click="anywhere"> | |||||
<img src="{{ asset(field.value.image) }}" class="img-fluid"> | |||||
</a> | |||||
<div id="{{ html_id }}" class="ea-lightbox"> | |||||
<img src="{{ asset(field.value.image) }}"> | |||||
</div> |
<div class="modal fade" id="lc-filemanager-modal" tabindex="-1" role="dialog" aria-labelledby="File manager modal"> | |||||
<div class="modal-dialog modal-lg" role="document"> | |||||
<div class="modal-content"> | |||||
<div class="modal-header"> | |||||
<h4 class="modal-title">Gestionaire de fichier</h4> | |||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close"> | |||||
<span aria-hidden="true">×</span> | |||||
</button> | |||||
</div> | |||||
<div class="modal-body"> | |||||
<iframe id="lc-filemanager-frame" src="" width="100%" height="500" frameborder="0"></iframe> | |||||
</div> | |||||
<div class="modal-footer"> | |||||
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button> | |||||
</div> | |||||
</div> | |||||
</div> | |||||
</div> |
{# @var ea \EasyCorp\Bundle\EasyAdminBundle\Context\AdminContext #} | |||||
{% use '@EasyAdmin/crud/form_theme.html.twig' %} | |||||
{% block gallery_manager_row %} | |||||
{{ block('collection_row') }} | |||||
{% endblock gallery_manager_row %} | |||||
{% block gallery_manager_widget %} | |||||
{{ block('collection_widget') }} | |||||
{% endblock gallery_manager_widget %} | |||||
{% block collection_row %} | |||||
{% if prototype is defined and not prototype.rendered %} | |||||
{% set row_attr = row_attr|merge({ 'data-prototype': form_row(prototype) }) %} | |||||
{% endif %} | |||||
{% set row_attr = row_attr|merge({ | |||||
'data-entry-is-complex': form.vars.ea_crud_form.ea_field and form.vars.ea_crud_form.ea_field.customOptions.get('entryIsComplex') ? 'true' : 'false', | |||||
'data-allow-add': allow_add ? 'true' : 'false', | |||||
'data-allow-delete': allow_delete ? 'true' : 'false', | |||||
'data-num-items': form.children|length, | |||||
'data-form-type-name-placeholder': prototype is defined ? prototype.vars.name : '', | |||||
}) %} | |||||
{{ block('form_row') }} | |||||
{% endblock collection_row %} | |||||
{% block collection_widget %} | |||||
{{ block('form_widget') }} | |||||
{% if allow_add|default(false) %} | |||||
<button type="button" class="btn btn-link field-collection-add"> | |||||
<i class="fa fa-plus pr-1"></i> | |||||
{{ 'action.add_new_item'|trans({}, 'EasyAdminBundle') }} | |||||
</button> | |||||
{% endif %} | |||||
{% endblock collection_widget %} | |||||
{% block collection_entry_widget %} | |||||
{% set is_complex = form_parent(form).vars.ea_crud_form.ea_field.customOptions.get('entryIsComplex') ?? false %} | |||||
<div class="field-collection-item {{ is_complex ? 'field-collection-item-complex' }}"> | |||||
{{ form_widget(form) }} | |||||
{% if form_parent(form).vars.allow_delete|default(false) %} | |||||
<button type="button" class="btn btn-link field-collection-delete" | |||||
title="{{ 'action.remove_item'|trans({}, 'EasyAdminBundle') }}"> | |||||
<i class="fas fa-times"></i> | |||||
</button> | |||||
{% endif %} | |||||
</div> | |||||
{% endblock collection_entry_widget %} | |||||
{% block file_manager_image_row %} | |||||
{{ form_widget(form) }} | |||||
{% endblock file_manager_image_row %} | |||||
{% block file_manager_legend_row %} | |||||
{{ form_widget(form) }} | |||||
{% endblock file_manager_legend_row %} | |||||
{% block file_manager_position_row %} | |||||
{{ form_widget(form) }} | |||||
{% endblock file_manager_position_row %} | |||||
{% block file_manager_widget %} | |||||
<div class="lc-filemanager col-xs-12"> | |||||
<div class="col-md-6 col-xs-12 nopadding" style="padding: 0px;"> | |||||
<img style="width: 200px; height: 150px; object-fit: contain; background: #ddd; " src="{{ form.image.vars.value }}" class="lc-filemenager-preview" id="{{ form.image.vars.id }}_preview" alt=""> | |||||
</div> | |||||
<div class="input-group"> | |||||
{{ form_widget(form) }} | |||||
<div class="input-group-append"> | |||||
<button type="button" class="btn btn-sm lc-filemanager-open" data-id="{{ form.image.vars.id }}" | |||||
data-target="{{ path('file_manager', {module:1, conf:'default'})|raw }}"> | |||||
<i class="fa fa-folder-open-o"></i> | |||||
</button> | |||||
{% if value %} | |||||
<button type="button" class="btn btn-sm lc-filemanager-delete" data-id="{{ form.image.vars.id }}"> | |||||
<i class="fa fa-trash-o"></i> | |||||
</button> | |||||
{% endif %} | |||||
{% if form.parent.vars['row_attr']['data-sortable'] is defined %} | |||||
<button type="button" class="btn btn-sm lc-btn-sortable" > | |||||
<i class="fa fa-arrows"></i> | |||||
</button> | |||||
{% endif %} | |||||
</div> | |||||
</div> | |||||
</div> | |||||
{% endblock file_manager_widget %} | |||||
{# @var ea \EasyCorp\Bundle\EasyAdminBundle\Context\AdminContext #} | |||||
{# @var entity \EasyCorp\Bundle\EasyAdminBundle\Dto\EntityDto #} | |||||
{% extends '@EasyAdmin/crud/new.html.twig' %} | |||||
{% block body_javascript %} | |||||
{{ parent() }} | |||||
{% include '@LcAdmin/crud/filemanager/file-manager-modal.html.twig' %} | |||||
{% endblock %} | |||||
{% extends '@EasyAdmin/page/content.html.twig' %} | |||||
{% block page_title 'LcAdminBundle' %} | |||||
{% block page_content %} | |||||
Bien sur votre tableau de bord | |||||
{% endblock %} | |||||
{ | |||||
"name": "lc/admin-bundle", | |||||
"type": "symfony-bundle", | |||||
"description": "Administration for Symfony applications based on easyadmin", | |||||
"keywords": ["backend", "admin", "generator"], | |||||
"homepage": "https://gitea.laclic.fr/Laclic/AdminBundle", | |||||
"license": "MIT", | |||||
"authors": [ | |||||
{ | |||||
"name": "La clic !", | |||||
"homepage": "laclic.fr/" | |||||
} | |||||
], | |||||
"require": { | |||||
"php": ">=7.2.5", | |||||
"easycorp/easyadmin-bundle": "^3.0", | |||||
"artgris/filemanager-bundle": "^2.2", | |||||
"friendsofsymfony/ckeditor-bundle": "^2.2", | |||||
"stof/doctrine-extensions-bundle": "^1.5" | |||||
}, | |||||
"config": { | |||||
"sort-packages": true | |||||
} | |||||
} |