@@ -3,12 +3,54 @@ | |||
namespace Lc\AdminBundle\Controller\Admin; | |||
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\Controller\AbstractCrudController as EaAbstractCrudController; | |||
use EasyCorp\Bundle\EasyAdminBundle\Router\AdminUrlGenerator; | |||
use Lc\AdminBundle\IModel\Translation\TranslatableInterface; | |||
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 | |||
{ |
@@ -15,7 +15,7 @@ class DashboardController extends AbstractDashboardController | |||
public function index(): Response | |||
{ | |||
return parent::index(); | |||
return $this->render('@LcAdmin/dashboard.html.twig'); | |||
} | |||
public function configureDashboard(): Dashboard |
@@ -0,0 +1,31 @@ | |||
<?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; | |||
} | |||
} |
@@ -8,11 +8,21 @@ use Symfony\Component\DependencyInjection\Extension\Extension; | |||
use Symfony\Component\DependencyInjection\Extension\PrependExtensionInterface; | |||
use Symfony\Component\DependencyInjection\Loader\YamlFileLoader; | |||
class LcAdminExtension extends Extension implements PrependExtensionInterface | |||
{ | |||
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) |
@@ -0,0 +1,19 @@ | |||
<?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 | |||
} |
@@ -0,0 +1,63 @@ | |||
<?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); | |||
} | |||
} | |||
} |
@@ -0,0 +1,41 @@ | |||
<?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; | |||
} | |||
} |
@@ -0,0 +1,79 @@ | |||
<?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; | |||
} | |||
} |
@@ -0,0 +1,50 @@ | |||
<?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; | |||
} | |||
} |
@@ -0,0 +1,85 @@ | |||
<?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; | |||
} | |||
} |
@@ -0,0 +1,85 @@ | |||
<?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; | |||
} | |||
} |
@@ -2,10 +2,8 @@ | |||
namespace Lc\AdminBundle\IModel\Cms; | |||
interface ImageInterface | |||
interface FileInterface | |||
{ | |||
} |
@@ -0,0 +1,9 @@ | |||
<?php | |||
namespace Lc\AdminBundle\IModel\Translation; | |||
interface TranslatableInterface | |||
{ | |||
} |
@@ -74,11 +74,22 @@ class EntityManager | |||
return $this; | |||
} | |||
public function refresh(EntityInterface $entity): self | |||
{ | |||
$this->entityManager->refresh($entity); | |||
return $this; | |||
} | |||
protected function persist(EntityInterface $entity) | |||
{ | |||
$this->entityManager->persist($entity); | |||
} | |||
public function getClassMetadata($className){ | |||
return $this->entityManager->getClassMetadata($className); | |||
} | |||
public function getEntityName($className) | |||
{ | |||
if (substr($className, -9) === 'Interface') { |
@@ -10,6 +10,7 @@ use Lc\AdminBundle\IModel\Cms\SortableInterface; | |||
use Lc\AdminBundle\IModel\Cms\TimestampableInterface; | |||
use Lc\AdminBundle\IModel\Cms\StatusInterface; | |||
use Doctrine\ORM\Mapping as ORM; | |||
use Gedmo\Mapping\Annotation as Gedmo; | |||
use Lc\AdminBundle\IModel\EntityInterface; | |||
/** | |||
@@ -27,11 +28,13 @@ abstract class AbstractDocument implements BlameableInterface, SeoInterface, Slu | |||
use DevAliasTrait; | |||
/** | |||
* @Gedmo\Translatable | |||
* @ORM\Column(type="string", length=255) | |||
*/ | |||
protected $title; | |||
/** | |||
* @Gedmo\Translatable | |||
* @ORM\Column(type="text", nullable=true) | |||
*/ | |||
protected $description; |
@@ -0,0 +1,72 @@ | |||
<?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; | |||
} | |||
} |
@@ -1,52 +0,0 @@ | |||
<?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; | |||
} | |||
} |
@@ -0,0 +1,53 @@ | |||
<?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; | |||
} | |||
} |
@@ -18,7 +18,22 @@ Si tu démarres un nouveau projet il te suffit de cloner le projet : https://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 ! | |||
### Pour les projet Aquarium, Laclic, Le plat pentu (et peut être d'autres) suit cette préocédure : |
@@ -3,68 +3,91 @@ | |||
namespace Lc\AdminBundle\Repository; | |||
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepositoryInterface; | |||
use Doctrine\ORM\AbstractQuery; | |||
use Doctrine\ORM\EntityManagerInterface; | |||
use Doctrine\ORM\EntityRepository; | |||
use Doctrine\ORM\Query; | |||
use Doctrine\ORM\QueryBuilder; | |||
use Gedmo\Translatable\TranslatableListener; | |||
use Lc\AdminBundle\IModel\Cms\StatusInterface; | |||
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) | |||
{ | |||
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() | |||
{ | |||
return $this->findBy(array()); |
@@ -0,0 +1,20 @@ | |||
<?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; | |||
} | |||
} |
@@ -0,0 +1,93 @@ | |||
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); | |||
}); | |||
}); | |||
} | |||
} |
@@ -0,0 +1,29 @@ | |||
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'); | |||
}); | |||
} |
@@ -0,0 +1,57 @@ | |||
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; | |||
} |
@@ -0,0 +1,21 @@ | |||
{# @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 %} |
@@ -0,0 +1,8 @@ | |||
{# @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 %} |
@@ -0,0 +1,11 @@ | |||
{# @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 %} |
@@ -0,0 +1,9 @@ | |||
{# @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 %} |
@@ -0,0 +1,11 @@ | |||
{# @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> |
@@ -0,0 +1,18 @@ | |||
<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> |
@@ -0,0 +1,100 @@ | |||
{# @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 %} | |||
@@ -0,0 +1,9 @@ | |||
{# @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 %} | |||
@@ -0,0 +1,9 @@ | |||
{% extends '@EasyAdmin/page/content.html.twig' %} | |||
{% block page_title 'LcAdminBundle' %} | |||
{% block page_content %} | |||
Bien sur votre tableau de bord | |||
{% endblock %} | |||
@@ -0,0 +1,24 @@ | |||
{ | |||
"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 | |||
} | |||
} |