@@ -4,6 +4,7 @@ namespace Lc\SovBundle\Authenticator; | |||
use Lc\SovBundle\Model\User\UserInterface; | |||
use Lc\SovBundle\Doctrine\EntityManager; | |||
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface; | |||
use Symfony\Component\HttpFoundation\RedirectResponse; | |||
use Symfony\Component\HttpFoundation\Request; | |||
use Symfony\Component\Security\Core\User\UserInterface as SfUserInterface; | |||
@@ -30,35 +31,39 @@ class LoginFormAuthenticator extends AbstractFormLoginAuthenticator implements P | |||
private $urlGenerator; | |||
private $csrfTokenManager; | |||
private $passwordEncoder; | |||
protected $parameterBag; | |||
public function __construct( | |||
EntityManager $entityManager, | |||
UrlGeneratorInterface $urlGenerator, | |||
CsrfTokenManagerInterface $csrfTokenManager, | |||
UserPasswordEncoderInterface $passwordEncoder | |||
) { | |||
EntityManager $entityManager, | |||
UrlGeneratorInterface $urlGenerator, | |||
CsrfTokenManagerInterface $csrfTokenManager, | |||
UserPasswordEncoderInterface $passwordEncoder, | |||
ParameterBagInterface $parameterBag | |||
) | |||
{ | |||
$this->entityManager = $entityManager; | |||
$this->urlGenerator = $urlGenerator; | |||
$this->csrfTokenManager = $csrfTokenManager; | |||
$this->passwordEncoder = $passwordEncoder; | |||
$this->parameterBag = $parameterBag; | |||
} | |||
public function supports(Request $request) | |||
{ | |||
return self::LOGIN_ROUTE === $request->attributes->get('_route') | |||
&& $request->isMethod('POST'); | |||
&& $request->isMethod('POST'); | |||
} | |||
public function getCredentials(Request $request) | |||
{ | |||
$credentials = [ | |||
'email' => $request->request->get('email'), | |||
'password' => $request->request->get('password'), | |||
'csrf_token' => $request->request->get('_csrf_token'), | |||
'email' => $request->request->get('email'), | |||
'password' => $request->request->get('password'), | |||
'csrf_token' => $request->request->get('_csrf_token'), | |||
]; | |||
$request->getSession()->set( | |||
Security::LAST_USERNAME, | |||
$credentials['email'] | |||
Security::LAST_USERNAME, | |||
$credentials['email'] | |||
); | |||
return $credentials; | |||
@@ -72,7 +77,7 @@ class LoginFormAuthenticator extends AbstractFormLoginAuthenticator implements P | |||
} | |||
$user = $this->entityManager->getRepository(UserInterface::class)->findOneBy( | |||
['email' => $credentials['email']] | |||
['email' => $credentials['email']] | |||
); | |||
if (!$user) { | |||
@@ -100,13 +105,31 @@ class LoginFormAuthenticator extends AbstractFormLoginAuthenticator implements P | |||
{ | |||
$routeName = 'home'; | |||
$email = $request->request->get('email'); | |||
$user = $this->entityManager->getRepository(UserInterface::class)->findOneBy(['email' => $email]); | |||
if ($user && ($user->hasRole('ROLE_ADMIN') || $user->hasRole('ROLE_SUPER_ADMIN'))) { | |||
$routeName = 'admin_dashboard'; | |||
$loginRedirection = $this->parameterBag->get('lc_sov.login_redirection'); | |||
$useReferer = $loginRedirection['redirect_referer']; | |||
$rolesRedirection = $loginRedirection['roles_redirection']; | |||
if (isset($useReferer) && $useReferer == true) { | |||
$url = $request->request->get('_target_path'); | |||
} else { | |||
$user = $this->entityManager->getRepository(UserInterface::class)->findOneBy(['email' => $email]); | |||
if (!empty($user)) { | |||
$roles = $user->getRoles(); | |||
foreach ($rolesRedirection as $roleRedirect) { | |||
if (in_array($roleRedirect['role'], $roles)) { | |||
$routeName = $roleRedirect['redirect']; | |||
} | |||
} | |||
} | |||
} | |||
return new RedirectResponse($this->urlGenerator->generate($routeName)); | |||
if (isset($url) && !empty($url)) { | |||
return new RedirectResponse($url); | |||
} else { | |||
return new RedirectResponse($this->urlGenerator->generate($routeName)); | |||
} | |||
} | |||
protected function getLoginUrl() |
@@ -0,0 +1,29 @@ | |||
<?php | |||
namespace Lc\SovBundle\Builder\Ticket; | |||
use Lc\SovBundle\Component\FormComponent; | |||
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface; | |||
class TicketBuilder | |||
{ | |||
protected FormComponent $formComponent; | |||
protected ParameterBagInterface $parameterBag; | |||
public function __construct(FormComponent $formComponent, ParameterBagInterface $parameterBag) | |||
{ | |||
$this->formComponent = $formComponent; | |||
$this->parameterBag = $parameterBag; | |||
} | |||
// uploadImageTicketMessage | |||
public function uploadImageTicketMessage($formTicket): ?string | |||
{ | |||
return $this->formComponent->uploadFile( | |||
$formTicket, | |||
'image', | |||
$this->parameterBag->get('app.ticket_images_directory'), | |||
$this->parameterBag->get('app.ticket_images_subdirectory') | |||
); | |||
} | |||
} |
@@ -0,0 +1,29 @@ | |||
<?php | |||
namespace Lc\SovBundle\Builder\User; | |||
use Doctrine\ORM\EntityManagerInterface; | |||
use Lc\SovBundle\Model\Newsletter\NewsletterInterface; | |||
use Lc\SovBundle\Model\User\UserInterface; | |||
class UserBuilder | |||
{ | |||
protected EntityManagerInterface $entityManager; | |||
public function __construct(EntityManagerInterface $entityManager) | |||
{ | |||
$this->entityManager = $entityManager; | |||
} | |||
public function setNewsletter(UserInterface $user, NewsletterInterface $newsletter, bool $subscribeNewsletter): void | |||
{ | |||
if ($subscribeNewsletter) { | |||
$user->addNewsletter($newsletter); | |||
} else { | |||
$user->removeNewsletter($newsletter); | |||
} | |||
$this->entityManager->persist($user); | |||
$this->entityManager->flush(); | |||
} | |||
} |
@@ -0,0 +1,134 @@ | |||
<?php | |||
namespace Lc\SovBundle\Component; | |||
use Geocoder\Model\Coordinates; | |||
use Geocoder\Provider\Addok\Addok; | |||
use Geocoder\Provider\GoogleMaps\GoogleMaps; | |||
use Geocoder\Provider\Nominatim\Nominatim; | |||
use Geocoder\Query\GeocodeQuery; | |||
use Geocoder\Query\ReverseQuery; | |||
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface; | |||
use Symfony\Component\HttpClient\HttplugClient; | |||
class CitiesComponent | |||
{ | |||
protected ParameterBagInterface $parameterBag; | |||
public function __construct(ParameterBagInterface $parameterBag) | |||
{ | |||
$this->parameterBag = $parameterBag; | |||
} | |||
public function callCitiesApi($method, $url, $data = false) | |||
{ | |||
$url = 'https://geo.api.gouv.fr/' . $url; | |||
$curl = curl_init(); | |||
switch ($method) { | |||
case "POST": | |||
curl_setopt($curl, CURLOPT_POST, 1); | |||
if ($data) { | |||
curl_setopt($curl, CURLOPT_POSTFIELDS, $data); | |||
} | |||
break; | |||
case "PUT": | |||
curl_setopt($curl, CURLOPT_PUT, 1); | |||
break; | |||
default: | |||
if ($data) { | |||
$url = sprintf("%s?%s", $url, http_build_query($data)); | |||
} | |||
} | |||
// Optional Authentication: | |||
curl_setopt($curl, CURLOPT_HTTPAUTH, CURLAUTH_BASIC); | |||
curl_setopt($curl, CURLOPT_USERPWD, "username:password"); | |||
curl_setopt($curl, CURLOPT_URL, $url); | |||
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1); | |||
$result = curl_exec($curl); | |||
curl_close($curl); | |||
return $result; | |||
} | |||
public function getGeocoderProvider() | |||
{ | |||
$provider = false; | |||
$symfonyClient = new HttplugClient(); | |||
$configGeocoderProvider = $this->parameterBag->get('geocoder.provider'); | |||
/* API du gouvernement */ | |||
if ($configGeocoderProvider == 'addok') { | |||
$provider = new Addok($symfonyClient, 'https://api-adresse.data.gouv.fr'); | |||
} /* Google Maps */ | |||
elseif ($configGeocoderProvider == 'googlemaps') { | |||
$provider = new GoogleMaps($symfonyClient, null, $this->parameterBag->get('geocoder.api_key')); | |||
} /* Nominatim : OpenStreetMap */ | |||
elseif ($configGeocoderProvider == 'nominatim') { | |||
$provider = Nominatim::withOpenStreetMapServer( | |||
$symfonyClient, | |||
'Mozilla/5.0 (platform; rv:geckoversion) Gecko/geckotrail Firefox/firefoxversion' | |||
); | |||
} | |||
if (!$provider) { | |||
throw new \ErrorException('Aucun provider (geocoding) défini'); | |||
} | |||
return $provider; | |||
} | |||
public function callAddressApi($query) | |||
{ | |||
$provider = $this->getGeocoderProvider() ;; | |||
$query = GeocodeQuery::create($query)->withData('type', 'housenumber'); | |||
$results = $provider->geocodeQuery($query); | |||
$resultsToReturn = array(); | |||
foreach($results as $result) { | |||
if ($result->getStreetNumber() && strlen($result->getStreetNumber()) > 0) { | |||
$resultsToReturn[] = $result; | |||
} | |||
} | |||
return $resultsToReturn; | |||
} | |||
public function callReverseAddressApi($latitude, $longitude) | |||
{ | |||
$provider = $this->getGeocoderProvider() ;; | |||
$query = ReverseQuery::create(new Coordinates($latitude, $longitude)); | |||
$results = $provider->reverseQuery($query); | |||
return $results->all() ; | |||
} | |||
public function getZipByCity($city, $code = null) | |||
{ | |||
$zip = null; | |||
$paramsSearch = [ | |||
'nom' => $city, | |||
'fields' => 'nom,codesPostaux' | |||
]; | |||
if ($code != null && $code != 0) { | |||
$paramsSearch['code'] = $code; | |||
} | |||
$returnCitiesSearchZip = json_decode($this->callCitiesApi('get', 'communes', $paramsSearch)); | |||
if ($returnCitiesSearchZip) { | |||
foreach ($returnCitiesSearchZip as $citySearchZip) { | |||
if (strtolower(trim($city)) == strtolower(trim($citySearchZip->nom))) { | |||
$zip = $citySearchZip->codesPostaux[0]; | |||
} | |||
} | |||
} | |||
return $zip; | |||
} | |||
} |
@@ -0,0 +1,33 @@ | |||
<?php | |||
namespace Lc\SovBundle\Component; | |||
use Lc\SovBundle\Resolver\UrlResolver; | |||
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface; | |||
class CookieComponent | |||
{ | |||
protected UrlResolver $urlResolver; | |||
protected ParameterBagInterface $parameterBag; | |||
public function __construct(UrlResolver $urlResolver, ParameterBagInterface $parameterBag) | |||
{ | |||
$this->urlResolver = $urlResolver; | |||
$this->parameterBag = $parameterBag; | |||
} | |||
public function getCookieDomain() | |||
{ | |||
return ($this->urlResolver->isServerLocalhost()) ? null : $this->parameterBag->get('app.cookie_domain_distant'); | |||
} | |||
public function cryptCookie($data) | |||
{ | |||
return base64_encode($data); | |||
} | |||
public function decryptCookie($data) | |||
{ | |||
return base64_decode($data); | |||
} | |||
} |
@@ -0,0 +1,68 @@ | |||
<?php | |||
namespace Lc\SovBundle\Component; | |||
class DateComponent | |||
{ | |||
public function date($format, $timestamp) | |||
{ | |||
setlocale(LC_TIME, 'fr_FR.UTF8', 'fr.UTF8', 'fr_FR.UTF-8', 'fr.UTF-8'); | |||
return strftime($format, $timestamp); | |||
} | |||
public function getNextDay($day) | |||
{ | |||
return new \DateTime('next ' . $day); | |||
} | |||
public function getNextDayByNumber($number) | |||
{ | |||
return $this->getNextDay($this->getDayByNumber($number, 'en')); | |||
} | |||
public function getDayByNumber($number, $lang = 'fr') | |||
{ | |||
if ($lang == 'fr') { | |||
$daysArray = [ | |||
1 => 'Lundi', | |||
2 => 'Mardi', | |||
3 => 'Mercredi', | |||
4 => 'Jeudi', | |||
5 => 'Vendredi', | |||
6 => 'Samedi', | |||
7 => 'Dimanche' | |||
]; | |||
} else { | |||
$daysArray = [ | |||
1 => 'Monday', | |||
2 => 'Tuesday', | |||
3 => 'Wednesday', | |||
4 => 'Thursday', | |||
5 => 'Friday', | |||
6 => 'Saturday', | |||
7 => 'Sunday', | |||
]; | |||
} | |||
if (isset($daysArray[$number])) { | |||
return $daysArray[$number]; | |||
} | |||
return ''; | |||
} | |||
// getDeliverySlotHour | |||
public function getHour(\DateTime $date) | |||
{ | |||
$timestamp = $date->getTimestamp() ; | |||
$hour = $this->date('%kh', $timestamp) ; | |||
$minutes = $this->date('%M', $timestamp) ; | |||
if($minutes != '00') { | |||
$hour .= $minutes ; | |||
} | |||
return $hour ; | |||
} | |||
} |
@@ -0,0 +1,94 @@ | |||
<?php | |||
namespace Lc\SovBundle\Component; | |||
use Doctrine\ORM\EntityManagerInterface; | |||
use Lc\SovBundle\Event\EntityComponentEvent; | |||
use Lc\SovBundle\Model\File\FileInterface; | |||
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface; | |||
use Symfony\Component\EventDispatcher\EventDispatcherInterface; | |||
class EntityComponent | |||
{ | |||
protected EntityManagerInterface $entityManager; | |||
protected ParameterBagInterface $parameterBag; | |||
protected EventDispatcherInterface $eventDispatcher; | |||
public function __construct( | |||
EntityManagerInterface $entityManager, | |||
ParameterBagInterface $parameterBag, | |||
EventDispatcherInterface $eventDispatcher | |||
) { | |||
$this->entityManager = $entityManager; | |||
$this->parameterBag = $parameterBag; | |||
$this->eventDispatcher = $eventDispatcher; | |||
} | |||
public function duplicateEntity($entity) | |||
{ | |||
$newEntity = clone $entity; | |||
$classMetadata = $this->entityManager->getClassMetadata(get_class($newEntity)); | |||
foreach ($classMetadata->getAssociationMappings() as $associationMapping){ | |||
if(in_array(FileInterface::class, class_implements($associationMapping['targetEntity']))){ | |||
$methodGet = 'get'.ucfirst($associationMapping['fieldName']); | |||
$methodSet = 'set'.ucfirst($associationMapping['fieldName']); | |||
if(method_exists($newEntity, $methodGet) && method_exists($newEntity, $methodSet)){ | |||
if(!is_null($newEntity->$methodGet())){ | |||
$newFile = clone $newEntity->$methodGet(); | |||
$newEntity->$methodSet($newFile); | |||
} | |||
} | |||
} | |||
} | |||
//TODO dispatch event duplicate | |||
/* if ($newEntity instanceof ProductFamilyInterface) { | |||
// @TODO : à adapter | |||
//$newEntity = $this->productFamilyUtils->processBeforePersistProductFamily($newEntity, false, true); | |||
} | |||
*/ | |||
$this->entityManager->create($newEntity); | |||
$this->eventDispatcher->dispatch(new EntityComponentEvent($newEntity), EntityComponentEvent::DUPLICATE_EVENT); | |||
return $newEntity; | |||
} | |||
public function duplicateEntityToOtherHub($entity, $hub) | |||
{ | |||
$newEntity = $this->duplicateEntity($entity); | |||
if ($hub) { | |||
$newEntity->setMerchant($hub); | |||
} | |||
$this->entityManager->persist($newEntity); | |||
$this->entityManager->flush(); | |||
return $newEntity; | |||
} | |||
public function duplicateImage($entity, $folder = false) | |||
{ | |||
$basePath = $this->parameterBag->get('kernel.project_dir') . '/public/uploads/images/'; | |||
if ($entity->getImage() && file_exists($basePath . $entity->getImage())) { | |||
$extension = strtolower(pathinfo($basePath . $entity->getImage(), PATHINFO_EXTENSION)); | |||
if ($extension == "jpg" || $extension == "png" || $extension == "gif") { | |||
$newImage = md5(uniqid()) . '.' . $extension; | |||
if ($folder) { | |||
$newImage = $folder . '/' . $newImage; | |||
} | |||
copy($basePath . $entity->getImage(), $basePath . $newImage); | |||
$entity->setImage($newImage); | |||
} else { | |||
$entity->setImage(null); | |||
} | |||
} else { | |||
$entity->setImage(null); | |||
} | |||
return $entity; | |||
} | |||
} |
@@ -0,0 +1,88 @@ | |||
<?php | |||
namespace Lc\SovBundle\Component; | |||
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface; | |||
class FileComponent | |||
{ | |||
protected ParameterBagInterface $parameterBag; | |||
public function __construct(ParameterBagInterface $parameterBag) | |||
{ | |||
$this->parameterBag = $parameterBag; | |||
} | |||
/** | |||
* Retourne le chemin vers le dossier d'uploads de responsiveFilemanager | |||
* | |||
* @return string | |||
*/ | |||
public function getFileManagerFolder() | |||
{ | |||
return $this->parameterBag->get('app.path.images'); | |||
} | |||
// lcLiip | |||
public function liip($path, $thumb = 'tile', $default = 'default.jpg') | |||
{ | |||
if (substr($path, 0, 1) === '/') $path = substr($path, 1); | |||
if ($path) { | |||
$fileManagerFolder = substr($this->getFileManagerFolder(), 1) ; | |||
if (strpos($path, $fileManagerFolder) === false) { | |||
$path = $fileManagerFolder . '/' . $path; | |||
} | |||
if (file_exists($path)) { | |||
return $this->liipCacheHelper->getBrowserPath($path, $thumb); | |||
} | |||
} | |||
return $this->liipCacheHelper->getBrowserPath($this->getFileManagerFolder() . '/' . $default, $thumb); | |||
} | |||
public function removeDir($dir) | |||
{ | |||
$files = array_diff(scandir($dir), array('.', '..')); | |||
foreach ($files as $file) { | |||
(is_dir("$dir/$file")) ? $this->removeDir("$dir/$file") : unlink("$dir/$file"); | |||
} | |||
return rmdir($dir); | |||
} | |||
function folderToZip($folder, &$zipFile, $subfolder = null) | |||
{ | |||
if ($zipFile == null) { | |||
// no resource given, exit | |||
return false; | |||
} | |||
// we check if $folder has a slash at its end, if not, we append one | |||
$tabFolder = str_split($folder); | |||
$tabSubFolder = str_split($subfolder); | |||
$folder .= end($tabFolder) == "/" ? "" : "/"; | |||
$subfolder .= end($tabSubFolder) == "/" ? "" : "/"; | |||
// we start by going through all files in $folder | |||
$handle = opendir($folder); | |||
while ($f = readdir($handle)) { | |||
if ($f != "." && $f != "..") { | |||
if (is_file($folder . $f)) { | |||
// if we find a file, store it | |||
// if we have a subfolder, store it there | |||
if ($subfolder != null) | |||
$zipFile->addFile($folder . $f, $subfolder . $f); | |||
else | |||
$zipFile->addFile($folder . $f); | |||
} elseif (is_dir($folder . $f)) { | |||
// if we find a folder, create a folder in the zip | |||
$zipFile->addEmptyDir($f); | |||
// and call the function again | |||
folderToZip($folder . $f, $zipFile, $f); | |||
} | |||
} | |||
} | |||
} | |||
} |
@@ -0,0 +1,58 @@ | |||
<?php | |||
namespace Lc\SovBundle\Component; | |||
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface; | |||
use Symfony\Component\Form\Extension\Core\Type\HiddenType; | |||
use Symfony\Component\Form\FormBuilderInterface; | |||
use Symfony\Component\HttpFoundation\File\Exception\FileException; | |||
class FormComponent | |||
{ | |||
protected ParameterBagInterface $parameterBag; | |||
public function __construct(ParameterBagInterface $parameterBag) | |||
{ | |||
$this->parameterBag = $parameterBag; | |||
} | |||
public function addCaptchaType(FormBuilderInterface $builder) | |||
{ | |||
$builder->add('specialField', HiddenType::class, [ | |||
'data' => 0, | |||
'mapped' => false, | |||
'attr' => [ | |||
'class' => 'special-field' | |||
], | |||
'constraints' => [ | |||
new NotNull(), | |||
new EqualTo(['value' => $this->parameterBag->get('app.captcha_value'), 'message' => 'Valeur incorrecte']) | |||
], | |||
]); | |||
} | |||
// uploadImageTicketMessage | |||
public function uploadFile($form, $child, $directory, $subdirectory): ?string | |||
{ | |||
$file = $form->get($child)->getData(); | |||
if ($file) { | |||
$originalFilename = pathinfo($file->getClientOriginalName(), PATHINFO_FILENAME); | |||
$newFilename = uniqid().'.'.$file->guessExtension(); | |||
try { | |||
$file->move( | |||
$directory, | |||
$newFilename | |||
); | |||
} catch (FileException $e) { | |||
throw new \ErrorException("Une erreur est survenue lors de l'upload du fichier."); | |||
} | |||
return $subdirectory.$newFilename; | |||
} | |||
return false; | |||
} | |||
} |
@@ -0,0 +1,78 @@ | |||
<?php | |||
namespace Lc\SovBundle\Component; | |||
class MetaComponent | |||
{ | |||
public function getMetaTitle($entity) | |||
{ | |||
if($entity) { | |||
if(method_exists($entity, 'getMetaTitle')) { | |||
return $entity->getMetaTitle() ; | |||
} | |||
elseif(method_exists($entity, 'getTitle')) { | |||
return $entity->getTitle() ; | |||
} | |||
} | |||
return '' ; | |||
} | |||
public function getMetaDescription($entity) | |||
{ | |||
if($entity) { | |||
if(method_exists($entity, 'getMetaDescription')) { | |||
return $entity->getMetaDescription() ; | |||
} | |||
elseif(method_exists($entity, 'getDescription')) { | |||
return $entity->getDescription() ; | |||
} | |||
} | |||
return '' ; | |||
} | |||
public function getOpenGraphTitle($entity) | |||
{ | |||
if($entity) { | |||
if(method_exists($entity, 'getOpenGraphTitle')) { | |||
return $entity->getOpenGraphTitle() ; | |||
} | |||
elseif(method_exists($entity, 'getTitle')) { | |||
return $entity->getTitle() ; | |||
} | |||
} | |||
return '' ; | |||
} | |||
public function getOpenGraphDescription($entity) | |||
{ | |||
if($entity) { | |||
if(method_exists($entity, 'getOpenGraphDescription')) { | |||
return $entity->getOpenGraphDescription() ; | |||
} | |||
elseif(method_exists($entity, 'getDescription')) { | |||
return $entity->getDescription() ; | |||
} | |||
} | |||
return '' ; | |||
} | |||
public function getOpenGraphImage($entity) | |||
{ | |||
if($entity) { | |||
if(method_exists($entity, 'getOpenGraphImage')) { | |||
return $entity->getOpenGraphImage() ; | |||
} | |||
elseif(method_exists($entity, 'getImage')) { | |||
return $entity->getImage() ; | |||
} | |||
} | |||
return '' ; | |||
} | |||
} |
@@ -0,0 +1,14 @@ | |||
<?php | |||
namespace Lc\SovBundle\Component; | |||
class NumberComponent | |||
{ | |||
public function round($price, $precision = 2) | |||
{ | |||
return round((($price * 100)) / 100, $precision); | |||
} | |||
} |
@@ -0,0 +1,77 @@ | |||
<?php | |||
namespace Lc\SovBundle\Component; | |||
class PointLocationComponent | |||
{ | |||
var $pointOnVertex = true; // Check if the point sits exactly on one of the vertices? | |||
function pointInPolygon($point, $polygon, $pointOnVertex = true) | |||
{ | |||
$this->pointOnVertex = $pointOnVertex; | |||
// Transform string coordinates into arrays with x and y values | |||
$point = $this->pointStringToCoordinates($point); | |||
$vertices = array(); | |||
foreach ($polygon as $vertex) { | |||
$vertices[] = $this->pointStringToCoordinates($vertex); | |||
} | |||
// Check if the point sits exactly on a vertex | |||
if ($this->pointOnVertex == true and $this->pointOnVertex($point, $vertices) == true) { | |||
return "vertex"; | |||
} | |||
// Check if the point is inside the polygon or on the boundary | |||
$intersections = 0; | |||
$vertices_count = count($vertices); | |||
for ($i = 1; $i < $vertices_count; $i++) { | |||
$vertex1 = $vertices[$i - 1]; | |||
$vertex2 = $vertices[$i]; | |||
if ($vertex1['y'] == $vertex2['y'] and $vertex1['y'] == $point['y'] and $point['x'] > min( | |||
$vertex1['x'], | |||
$vertex2['x'] | |||
) and $point['x'] < max( | |||
$vertex1['x'], | |||
$vertex2['x'] | |||
)) { // Check if point is on an horizontal polygon boundary | |||
return "boundary"; | |||
} | |||
if ($point['y'] > min($vertex1['y'], $vertex2['y']) and $point['y'] <= max( | |||
$vertex1['y'], | |||
$vertex2['y'] | |||
) and $point['x'] <= max($vertex1['x'], $vertex2['x']) and $vertex1['y'] != $vertex2['y']) { | |||
$xinters = ($point['y'] - $vertex1['y']) * ($vertex2['x'] - $vertex1['x']) / ($vertex2['y'] - $vertex1['y']) + $vertex1['x']; | |||
if ($xinters == $point['x']) { // Check if point is on the polygon boundary (other than horizontal) | |||
return "boundary"; | |||
} | |||
if ($vertex1['x'] == $vertex2['x'] || $point['x'] <= $xinters) { | |||
$intersections++; | |||
} | |||
} | |||
} | |||
// If the number of edges we passed through is odd, then it's in the polygon. | |||
if ($intersections % 2 != 0) { | |||
return "inside"; | |||
} else { | |||
return "outside"; | |||
} | |||
} | |||
function pointOnVertex($point, $vertices) | |||
{ | |||
foreach ($vertices as $vertex) { | |||
if ($point == $vertex) { | |||
return true; | |||
} | |||
} | |||
} | |||
function pointStringToCoordinates($pointString) | |||
{ | |||
$coordinates = explode(" ", $pointString); | |||
return array("x" => $coordinates[0], "y" => $coordinates[1]); | |||
} | |||
} |
@@ -0,0 +1,198 @@ | |||
<?php | |||
namespace Lc\SovBundle\Component; | |||
use Cocur\Slugify\Slugify; | |||
class StringComponent | |||
{ | |||
public function limitText($text, $limit) | |||
{ | |||
$text = strip_tags($text); | |||
if (str_word_count($text, 0) > $limit) { | |||
$words = str_word_count($text, 2); | |||
$pos = array_keys($words); | |||
$text = substr($text, 0, $pos[$limit]) . '...'; | |||
} | |||
return $text; | |||
} | |||
public function limitTextByLength($text, $length, $append = '...') | |||
{ | |||
if (strlen($text) > $length) { | |||
$text = substr($text, 0, $length) . $append; | |||
} | |||
return $text; | |||
} | |||
function truncateHtml($text, $length = 100, $ending = '...', $exact = false, $considerHtml = true) | |||
{ | |||
if ($considerHtml) { | |||
// if the plain text is shorter than the maximum length, return the whole text | |||
if (strlen(preg_replace('/<.*?>/', '', $text)) <= $length) { | |||
return $text; | |||
} | |||
// splits all html-tags to scanable lines | |||
preg_match_all('/(<.+?>)?([^<>]*)/s', $text, $lines, PREG_SET_ORDER); | |||
$total_length = strlen($ending); | |||
$open_tags = array(); | |||
$truncate = ''; | |||
foreach ($lines as $line_matchings) { | |||
// if there is any html-tag in this line, handle it and add it (uncounted) to the output | |||
if (!empty($line_matchings[1])) { | |||
// if it's an "empty element" with or without xhtml-conform closing slash | |||
if (preg_match( | |||
'/^<(\s*.+?\/\s*|\s*(img|br|input|hr|area|base|basefont|col|frame|isindex|link|meta|param)(\s.+?)?)>$/is', | |||
$line_matchings[1] | |||
)) { | |||
// do nothing | |||
// if tag is a closing tag | |||
} else { | |||
if (preg_match('/^<\s*\/([^\s]+?)\s*>$/s', $line_matchings[1], $tag_matchings)) { | |||
// delete tag from $open_tags list | |||
$pos = array_search($tag_matchings[1], $open_tags); | |||
if ($pos !== false) { | |||
unset($open_tags[$pos]); | |||
} | |||
// if tag is an opening tag | |||
} else { | |||
if (preg_match('/^<\s*([^\s>!]+).*?>$/s', $line_matchings[1], $tag_matchings)) { | |||
// add tag to the beginning of $open_tags list | |||
array_unshift($open_tags, strtolower($tag_matchings[1])); | |||
} | |||
} | |||
} | |||
// add html-tag to $truncate'd text | |||
$truncate .= $line_matchings[1]; | |||
} | |||
// calculate the length of the plain text part of the line; handle entities as one character | |||
$content_length = strlen( | |||
preg_replace('/&[0-9a-z]{2,8};|&#[0-9]{1,7};|[0-9a-f]{1,6};/i', ' ', $line_matchings[2]) | |||
); | |||
if ($total_length + $content_length > $length) { | |||
// the number of characters which are left | |||
$left = $length - $total_length; | |||
$entities_length = 0; | |||
// search for html entities | |||
if (preg_match_all( | |||
'/&[0-9a-z]{2,8};|&#[0-9]{1,7};|[0-9a-f]{1,6};/i', | |||
$line_matchings[2], | |||
$entities, | |||
PREG_OFFSET_CAPTURE | |||
)) { | |||
// calculate the real length of all entities in the legal range | |||
foreach ($entities[0] as $entity) { | |||
if ($entity[1] + 1 - $entities_length <= $left) { | |||
$left--; | |||
$entities_length += strlen($entity[0]); | |||
} else { | |||
// no more characters left | |||
break; | |||
} | |||
} | |||
} | |||
$truncate .= substr($line_matchings[2], 0, $left + $entities_length); | |||
// maximum lenght is reached, so get off the loop | |||
break; | |||
} else { | |||
$truncate .= $line_matchings[2]; | |||
$total_length += $content_length; | |||
} | |||
// if the maximum length is reached, get off the loop | |||
if ($total_length >= $length) { | |||
break; | |||
} | |||
} | |||
} else { | |||
if (strlen($text) <= $length) { | |||
return $text; | |||
} else { | |||
$truncate = substr($text, 0, $length - strlen($ending)); | |||
} | |||
} | |||
// if the words shouldn't be cut in the middle... | |||
if (!$exact) { | |||
// ...search the last occurance of a space... | |||
$spacepos = strrpos($truncate, ' '); | |||
if (isset($spacepos)) { | |||
// ...and cut the text in this position | |||
$truncate = substr($truncate, 0, $spacepos); | |||
} | |||
} | |||
// add the defined ending to the text | |||
$truncate .= $ending; | |||
if ($considerHtml) { | |||
// close all unclosed html-tags | |||
foreach ($open_tags as $tag) { | |||
$truncate .= '</' . $tag . '>'; | |||
} | |||
} | |||
return $truncate; | |||
} | |||
function stripAccents($stripAccents) | |||
{ | |||
return strtr( | |||
$stripAccents, | |||
'àáâãäçèéêëìíîïñòóôõöùúûüýÿÀÁÂÃÄÇÈÉÊËÌÍÎÏÑÒÓÔÕÖÙÚÛÜÝ', | |||
'aaaaaceeeeiiiinooooouuuuyyAAAAACEEEEIIIINOOOOOUUUUY' | |||
); | |||
} | |||
function cleanStringToCompare($string) | |||
{ | |||
return $this->stripAccents(trim(strtolower($string))); | |||
} | |||
public function slugify($string) | |||
{ | |||
$slugify = new Slugify(); | |||
return $slugify->slugify($string); | |||
} | |||
function camelCase($str) | |||
{ | |||
$i = array("-", "_"); | |||
$str = preg_replace('/([a-z])([A-Z])/', "\\1 \\2", $str); | |||
$str = preg_replace('@[^a-zA-Z0-9\-_ ]+@', '', $str); | |||
$str = str_replace($i, ' ', $str); | |||
$str = str_replace(' ', '', ucwords(strtolower($str))); | |||
$str = strtolower(substr($str, 0, 1)) . substr($str, 1); | |||
return $str; | |||
} | |||
function snakeCase($str) | |||
{ | |||
$str = preg_replace('/([a-z])([A-Z])/', "\\1_\\2", $str); | |||
$str = strtolower($str); | |||
return $str; | |||
} | |||
public function csvEscape($str) | |||
{ | |||
return str_replace(array("\r", "\n"), ' ', $str); | |||
} | |||
public function urlEncryptData($datas){ | |||
$key = 'secretToken'; | |||
foreach ($datas as $data) { | |||
$key .= $data; | |||
} | |||
return md5($key); | |||
} | |||
public function formatPhoneNumber($phone) | |||
{ | |||
$phone = preg_replace('`[^0-9]`', '', $phone); | |||
if(strlen($phone) == 10) { | |||
$phone = '+33'.substr($phone, 1, 9) ; | |||
} | |||
elseif(strlen($phone) == 11 && substr($phone, 0, 2) == '33') { | |||
$phone = '+'.$phone ; | |||
} | |||
return $phone ; | |||
} | |||
} |
@@ -0,0 +1,39 @@ | |||
<?php | |||
namespace Lc\SovBundle\Container\File; | |||
use Lc\SovBundle\Factory\File\FileFactory; | |||
use Lc\SovBundle\Repository\File\FileRepositoryQuery; | |||
use Lc\SovBundle\Repository\File\FileStore; | |||
class FileContainer | |||
{ | |||
protected FileFactory $factory; | |||
protected FileRepositoryQuery $repositoryQuery; | |||
protected FileStore $store; | |||
public function __construct( | |||
FileFactory $factory, | |||
FileRepositoryQuery $repositoryQuery, | |||
FileStore $store | |||
) { | |||
$this->factory = $factory; | |||
$this->repositoryQuery = $repositoryQuery; | |||
$this->store = $store; | |||
} | |||
public function getFactory(): FileFactory | |||
{ | |||
return $this->factory; | |||
} | |||
public function getRepositoryQuery(): FileRepositoryQuery | |||
{ | |||
return $this->repositoryQuery; | |||
} | |||
public function getStore(): FileStore | |||
{ | |||
return $this->store; | |||
} | |||
} |
@@ -0,0 +1,39 @@ | |||
<?php | |||
namespace Lc\SovBundle\Container\Newsletter; | |||
use Lc\SovBundle\Factory\Newsletter\NewsletterFactory; | |||
use Lc\SovBundle\Repository\Newsletter\NewsletterRepositoryQuery; | |||
use Lc\SovBundle\Repository\Newsletter\NewsletterStore; | |||
class NewsletterContainer | |||
{ | |||
protected NewsletterFactory $factory; | |||
protected NewsletterRepositoryQuery $repositoryQuery; | |||
protected NewsletterStore $store; | |||
public function __construct( | |||
NewsletterFactory $factory, | |||
NewsletterRepositoryQuery $repositoryQuery, | |||
NewsletterStore $store | |||
) { | |||
$this->factory = $factory; | |||
$this->repositoryQuery = $repositoryQuery; | |||
$this->store = $store; | |||
} | |||
public function getFactory(): NewsletterFactory | |||
{ | |||
return $this->factory; | |||
} | |||
public function getRepositoryQuery(): NewsletterRepositoryQuery | |||
{ | |||
return $this->repositoryQuery; | |||
} | |||
public function getStore(): NewsletterStore | |||
{ | |||
return $this->store; | |||
} | |||
} |
@@ -0,0 +1,39 @@ | |||
<?php | |||
namespace Lc\SovBundle\Container\Reminder; | |||
use Lc\SovBundle\Factory\Reminder\ReminderFactory; | |||
use Lc\SovBundle\Repository\Reminder\ReminderRepositoryQuery; | |||
use Lc\SovBundle\Repository\Reminder\ReminderStore; | |||
class ReminderContainer | |||
{ | |||
protected ReminderFactory $factory; | |||
protected ReminderRepositoryQuery $repositoryQuery; | |||
protected ReminderStore $store; | |||
public function __construct( | |||
ReminderFactory $factory, | |||
ReminderRepositoryQuery $repositoryQuery, | |||
ReminderStore $store | |||
) { | |||
$this->factory = $factory; | |||
$this->repositoryQuery = $repositoryQuery; | |||
$this->store = $store; | |||
} | |||
public function getFactory(): ReminderFactory | |||
{ | |||
return $this->factory; | |||
} | |||
public function getRepositoryQuery(): ReminderRepositoryQuery | |||
{ | |||
return $this->repositoryQuery; | |||
} | |||
public function getStore(): ReminderStore | |||
{ | |||
return $this->store; | |||
} | |||
} |
@@ -0,0 +1,57 @@ | |||
<?php | |||
namespace Lc\SovBundle\Container\Setting; | |||
use Lc\SovBundle\Definition\SiteSettingDefinition; | |||
use Lc\SovBundle\Factory\Setting\SiteSettingFactory; | |||
use Lc\SovBundle\Repository\Setting\SiteSettingRepositoryQuery; | |||
use Lc\SovBundle\Repository\Setting\SiteSettingStore; | |||
use Lc\SovBundle\Solver\Setting\SettingSolver; | |||
class SiteSettingContainer | |||
{ | |||
protected SiteSettingFactory $factory; | |||
protected SiteSettingDefinition $definition; | |||
protected SiteSettingRepositoryQuery $repositoryQuery; | |||
protected SiteSettingStore $store; | |||
protected SettingSolver $settingSolver; | |||
public function __construct( | |||
SiteSettingFactory $factory, | |||
SiteSettingDefinition $definition, | |||
SiteSettingRepositoryQuery $repositoryQuery, | |||
SiteSettingStore $store, | |||
SettingSolver $settingSolver | |||
) { | |||
$this->factory = $factory; | |||
$this->definition = $definition; | |||
$this->repositoryQuery = $repositoryQuery; | |||
$this->store = $store; | |||
$this->settingSolver = $settingSolver; | |||
} | |||
public function getFactory(): SiteSettingFactory | |||
{ | |||
return $this->factory; | |||
} | |||
public function getDefinition(): SiteSettingDefinition | |||
{ | |||
return $this->definition; | |||
} | |||
public function getRepositoryQuery(): SiteSettingRepositoryQuery | |||
{ | |||
return $this->repositoryQuery; | |||
} | |||
public function getStore(): SiteSettingStore | |||
{ | |||
return $this->store; | |||
} | |||
public function getSettingSolver(): SettingSolver | |||
{ | |||
return $this->settingSolver; | |||
} | |||
} |
@@ -0,0 +1,39 @@ | |||
<?php | |||
namespace Lc\SovBundle\Container\Site; | |||
use Lc\SovBundle\Factory\Site\NewsFactory; | |||
use Lc\SovBundle\Repository\Site\NewsRepositoryQuery; | |||
use Lc\SovBundle\Repository\Site\NewsStore; | |||
class NewsContainer | |||
{ | |||
protected NewsFactory $factory; | |||
protected NewsRepositoryQuery $repositoryQuery; | |||
protected NewsStore $store; | |||
public function __construct( | |||
NewsFactory $factory, | |||
NewsRepositoryQuery $repositoryQuery, | |||
NewsStore $store | |||
) { | |||
$this->factory = $factory; | |||
$this->repositoryQuery = $repositoryQuery; | |||
$this->store = $store; | |||
} | |||
public function getFactory(): NewsFactory | |||
{ | |||
return $this->factory; | |||
} | |||
public function getRepositoryQuery(): NewsRepositoryQuery | |||
{ | |||
return $this->repositoryQuery; | |||
} | |||
public function getStore(): NewsStore | |||
{ | |||
return $this->store; | |||
} | |||
} |
@@ -0,0 +1,39 @@ | |||
<?php | |||
namespace Lc\SovBundle\Container\Site; | |||
use Lc\SovBundle\Factory\Site\PageFactory; | |||
use Lc\SovBundle\Repository\Site\PageRepositoryQuery; | |||
use Lc\SovBundle\Repository\Site\PageStore; | |||
class PageContainer | |||
{ | |||
protected PageFactory $factory; | |||
protected PageRepositoryQuery $repositoryQuery; | |||
protected PageStore $store; | |||
public function __construct( | |||
PageFactory $factory, | |||
PageRepositoryQuery $repositoryQuery, | |||
PageStore $store | |||
) { | |||
$this->factory = $factory; | |||
$this->repositoryQuery = $repositoryQuery; | |||
$this->store = $store; | |||
} | |||
public function getFactory(): PageFactory | |||
{ | |||
return $this->factory; | |||
} | |||
public function getRepositoryQuery(): PageRepositoryQuery | |||
{ | |||
return $this->repositoryQuery; | |||
} | |||
public function getStore(): PageStore | |||
{ | |||
return $this->store; | |||
} | |||
} |
@@ -0,0 +1,39 @@ | |||
<?php | |||
namespace Lc\SovBundle\Container\Site; | |||
use Lc\SovBundle\Factory\Site\SiteFactory; | |||
use Lc\SovBundle\Repository\Site\SiteRepositoryQuery; | |||
use Lc\SovBundle\Repository\Site\SiteStore; | |||
class SiteContainer | |||
{ | |||
protected SiteFactory $factory; | |||
protected SiteRepositoryQuery $repositoryQuery; | |||
protected SiteStore $store; | |||
public function __construct( | |||
SiteFactory $factory, | |||
SiteRepositoryQuery $repositoryQuery, | |||
SiteStore $store | |||
) { | |||
$this->factory = $factory; | |||
$this->repositoryQuery = $repositoryQuery; | |||
$this->store = $store; | |||
} | |||
public function getFactory(): SiteFactory | |||
{ | |||
return $this->factory; | |||
} | |||
public function getRepositoryQuery(): SiteRepositoryQuery | |||
{ | |||
return $this->repositoryQuery; | |||
} | |||
public function getStore(): SiteStore | |||
{ | |||
return $this->store; | |||
} | |||
} |
@@ -0,0 +1,57 @@ | |||
<?php | |||
namespace Lc\SovBundle\Container\Ticket; | |||
use Lc\SovBundle\Builder\Ticket\TicketBuilder; | |||
use Lc\SovBundle\Factory\Ticket\TicketFactory; | |||
use Lc\SovBundle\Repository\Ticket\TicketRepositoryQuery; | |||
use Lc\SovBundle\Repository\Ticket\TicketStore; | |||
use Lc\SovBundle\Solver\Ticket\TicketSolver; | |||
class TicketContainer | |||
{ | |||
protected TicketFactory $factory; | |||
protected TicketBuilder $builder; | |||
protected TicketRepositoryQuery $repositoryQuery; | |||
protected TicketStore $store; | |||
protected TicketSolver $solver; | |||
public function __construct( | |||
TicketFactory $factory, | |||
TicketBuilder $builder, | |||
TicketRepositoryQuery $repositoryQuery, | |||
TicketStore $store, | |||
TicketSolver $solver | |||
) { | |||
$this->factory = $factory; | |||
$this->builder = $builder; | |||
$this->repositoryQuery = $repositoryQuery; | |||
$this->store = $store; | |||
$this->solver = $solver; | |||
} | |||
public function getFactory(): TicketFactory | |||
{ | |||
return $this->factory; | |||
} | |||
public function getBuilder(): TicketBuilder | |||
{ | |||
return $this->builder; | |||
} | |||
public function getRepositoryQuery(): TicketRepositoryQuery | |||
{ | |||
return $this->repositoryQuery; | |||
} | |||
public function getStore(): TicketStore | |||
{ | |||
return $this->store; | |||
} | |||
public function getSolver(): TicketSolver | |||
{ | |||
return $this->solver; | |||
} | |||
} |
@@ -0,0 +1,39 @@ | |||
<?php | |||
namespace Lc\SovBundle\Container\Ticket; | |||
use Lc\SovBundle\Factory\Ticket\TicketMessageFactory; | |||
use Lc\SovBundle\Repository\Ticket\TicketMessageRepositoryQuery; | |||
use Lc\SovBundle\Repository\Ticket\TicketMessageStore; | |||
class TicketMessageContainer | |||
{ | |||
protected TicketMessageFactory $factory; | |||
protected TicketMessageRepositoryQuery $repositoryQuery; | |||
protected TicketMessageStore $store; | |||
public function __construct( | |||
TicketMessageFactory $factory, | |||
TicketMessageRepositoryQuery $repositoryQuery, | |||
TicketMessageStore $store | |||
) { | |||
$this->factory = $factory; | |||
$this->repositoryQuery = $repositoryQuery; | |||
$this->store = $store; | |||
} | |||
public function getFactory(): TicketMessageFactory | |||
{ | |||
return $this->factory; | |||
} | |||
public function getRepositoryQuery(): TicketMessageRepositoryQuery | |||
{ | |||
return $this->repositoryQuery; | |||
} | |||
public function getStore(): TicketMessageStore | |||
{ | |||
return $this->store; | |||
} | |||
} |
@@ -0,0 +1,39 @@ | |||
<?php | |||
namespace Lc\SovBundle\Container\User; | |||
use Lc\SovBundle\Factory\User\GroupUserFactory; | |||
use Lc\SovBundle\Repository\User\GroupUserRepositoryQuery; | |||
use Lc\SovBundle\Repository\User\GroupUserStore; | |||
class GroupUserContainer | |||
{ | |||
protected GroupUserFactory $factory; | |||
protected GroupUserRepositoryQuery $repositoryQuery; | |||
protected GroupUserStore $store; | |||
public function __construct( | |||
GroupUserFactory $factory, | |||
GroupUserRepositoryQuery $repositoryQuery, | |||
GroupUserStore $store | |||
) { | |||
$this->factory = $factory; | |||
$this->repositoryQuery = $repositoryQuery; | |||
$this->store = $store; | |||
} | |||
public function getFactory(): GroupUserFactory | |||
{ | |||
return $this->factory; | |||
} | |||
public function getRepositoryQuery(): GroupUserRepositoryQuery | |||
{ | |||
return $this->repositoryQuery; | |||
} | |||
public function getStore(): GroupUserStore | |||
{ | |||
return $this->store; | |||
} | |||
} |
@@ -0,0 +1,48 @@ | |||
<?php | |||
namespace Lc\SovBundle\Container\User; | |||
use Lc\SovBundle\Builder\User\UserBuilder; | |||
use Lc\SovBundle\Factory\User\UserFactory; | |||
use Lc\SovBundle\Repository\User\UserRepositoryQuery; | |||
use Lc\SovBundle\Repository\User\UserStore; | |||
class UserContainer | |||
{ | |||
protected UserFactory $factory; | |||
protected UserBuilder $builder; | |||
protected UserRepositoryQuery $repositoryQuery; | |||
protected UserStore $store; | |||
public function __construct( | |||
UserFactory $factory, | |||
UserBuilder $builder, | |||
UserRepositoryQuery $repositoryQuery, | |||
UserStore $store | |||
) { | |||
$this->factory = $factory; | |||
$this->builder = $builder; | |||
$this->repositoryQuery = $repositoryQuery; | |||
$this->store = $store; | |||
} | |||
public function getFactory(): UserFactory | |||
{ | |||
return $this->factory; | |||
} | |||
public function getBuilder(): UserBuilder | |||
{ | |||
return $this->builder; | |||
} | |||
public function getRepositoryQuery(): UserRepositoryQuery | |||
{ | |||
return $this->repositoryQuery; | |||
} | |||
public function getStore(): UserStore | |||
{ | |||
return $this->store; | |||
} | |||
} |
@@ -0,0 +1,773 @@ | |||
<?php | |||
namespace Lc\SovBundle\Controller; | |||
use Doctrine\ORM\EntityManagerInterface; | |||
use Doctrine\ORM\QueryBuilder; | |||
use EasyCorp\Bundle\EasyAdminBundle\Collection\ActionCollection; | |||
use EasyCorp\Bundle\EasyAdminBundle\Collection\EntityCollection; | |||
use EasyCorp\Bundle\EasyAdminBundle\Collection\FieldCollection; | |||
use EasyCorp\Bundle\EasyAdminBundle\Collection\FilterCollection; | |||
use EasyCorp\Bundle\EasyAdminBundle\Config\Action; | |||
use EasyCorp\Bundle\EasyAdminBundle\Config\Actions; | |||
use EasyCorp\Bundle\EasyAdminBundle\Config\Crud; | |||
use EasyCorp\Bundle\EasyAdminBundle\Config\KeyValueStore; | |||
use EasyCorp\Bundle\EasyAdminBundle\Config\Option\EA; | |||
use EasyCorp\Bundle\EasyAdminBundle\Context\AdminContext; | |||
use EasyCorp\Bundle\EasyAdminBundle\Contracts\Controller\CrudControllerInterface; | |||
use EasyCorp\Bundle\EasyAdminBundle\Controller\AbstractCrudController as EaAbstractCrudController; | |||
use EasyCorp\Bundle\EasyAdminBundle\Dto\EntityDto; | |||
use EasyCorp\Bundle\EasyAdminBundle\Dto\FieldDto; | |||
use EasyCorp\Bundle\EasyAdminBundle\Dto\SearchDto; | |||
use EasyCorp\Bundle\EasyAdminBundle\Event\AfterCrudActionEvent; | |||
use EasyCorp\Bundle\EasyAdminBundle\Event\AfterEntityUpdatedEvent; | |||
use EasyCorp\Bundle\EasyAdminBundle\Event\BeforeCrudActionEvent; | |||
use EasyCorp\Bundle\EasyAdminBundle\Event\BeforeEntityDeletedEvent; | |||
use EasyCorp\Bundle\EasyAdminBundle\Exception\ForbiddenActionException; | |||
use EasyCorp\Bundle\EasyAdminBundle\Exception\InsufficientEntityPermissionException; | |||
use EasyCorp\Bundle\EasyAdminBundle\Factory\ControllerFactory; | |||
use EasyCorp\Bundle\EasyAdminBundle\Factory\EntityFactory; | |||
use EasyCorp\Bundle\EasyAdminBundle\Factory\FilterFactory; | |||
use EasyCorp\Bundle\EasyAdminBundle\Factory\PaginatorFactory; | |||
use EasyCorp\Bundle\EasyAdminBundle\Field\AssociationField; | |||
use EasyCorp\Bundle\EasyAdminBundle\Field\FormField; | |||
use EasyCorp\Bundle\EasyAdminBundle\Field\TextareaField; | |||
use EasyCorp\Bundle\EasyAdminBundle\Field\TextField; | |||
use EasyCorp\Bundle\EasyAdminBundle\Provider\AdminContextProvider; | |||
use EasyCorp\Bundle\EasyAdminBundle\Router\AdminUrlGenerator; | |||
use EasyCorp\Bundle\EasyAdminBundle\Security\Permission; | |||
use Lc\SovBundle\Component\EntityComponent; | |||
use Lc\SovBundle\Container\File\FileContainer; | |||
use Lc\SovBundle\Container\Newsletter\NewsletterContainer; | |||
use Lc\SovBundle\Container\Reminder\ReminderContainer; | |||
use Lc\SovBundle\Container\Setting\SiteSettingContainer; | |||
use Lc\SovBundle\Container\Site\NewsContainer; | |||
use Lc\SovBundle\Container\Site\PageContainer; | |||
use Lc\SovBundle\Container\Site\SiteContainer; | |||
use Lc\SovBundle\Container\Ticket\TicketContainer; | |||
use Lc\SovBundle\Container\Ticket\TicketMessageContainer; | |||
use Lc\SovBundle\Container\User\GroupUserContainer; | |||
use Lc\SovBundle\Container\User\UserContainer; | |||
use Lc\SovBundle\Doctrine\Extension\DevAliasInterface; | |||
use Lc\SovBundle\Doctrine\Extension\SeoInterface; | |||
use Lc\SovBundle\Doctrine\Extension\SortableInterface; | |||
use Lc\SovBundle\Doctrine\Extension\TranslatableInterface; | |||
use Lc\SovBundle\Doctrine\Extension\TreeInterface; | |||
use Lc\SovBundle\Field\CollectionField; | |||
use Lc\SovBundle\Field\Filter\FilterManager; | |||
use Lc\SovBundle\Form\Common\FiltersFormType; | |||
use Lc\SovBundle\Form\Common\PositionType; | |||
use Lc\SovBundle\Translation\TranslatorAdmin; | |||
use Symfony\Component\Form\Extension\Core\Type\ChoiceType; | |||
use Symfony\Component\Form\Extension\Core\Type\CollectionType; | |||
use Symfony\Component\Form\Extension\Core\Type\DateTimeType; | |||
use Symfony\Component\Form\Extension\Core\Type\DateType; | |||
use Symfony\Component\Form\Extension\Core\Type\IntegerType; | |||
use Symfony\Component\Form\Extension\Core\Type\TextType; | |||
use Symfony\Component\Form\FormInterface; | |||
use Symfony\Component\HttpFoundation\JsonResponse; | |||
use Symfony\Component\HttpFoundation\RequestStack; | |||
use Symfony\Component\HttpFoundation\Session\SessionInterface; | |||
abstract class AbstractAdminController extends EaAbstractCrudController | |||
{ | |||
protected FormInterface $filtersForm; | |||
public static function getSubscribedServices() | |||
{ | |||
return array_merge( | |||
parent::getSubscribedServices(), | |||
[ | |||
TranslatorAdmin::class => TranslatorAdmin::class, | |||
SessionInterface::class => SessionInterface::class, | |||
RequestStack::class => RequestStack::class, | |||
EntityManagerInterface::class => EntityManagerInterface::class, | |||
FilterManager::class => FilterManager::class, | |||
FileContainer::class => FileContainer::class, | |||
NewsletterContainer::class => NewsletterContainer::class, | |||
ReminderContainer::class => ReminderContainer::class, | |||
NewsContainer::class => NewsContainer::class, | |||
PageContainer::class => PageContainer::class, | |||
SiteContainer::class => SiteContainer::class, | |||
TicketContainer::class => TicketContainer::class, | |||
TicketMessageContainer::class => TicketMessageContainer::class, | |||
GroupUserContainer::class => GroupUserContainer::class, | |||
UserContainer::class => UserContainer::class, | |||
SiteSettingContainer::class => SiteSettingContainer::class, | |||
] | |||
); | |||
} | |||
public function configureResponseParameters(KeyValueStore $responseParameters): KeyValueStore | |||
{ | |||
$this->overrideGlobalActions($responseParameters->get('global_actions')); | |||
$this->overrideEntitiesActions($responseParameters->get('entities')); | |||
if (Crud::PAGE_INDEX === $responseParameters->get('pageName')) { | |||
$responseParameters->set('fields', $this->configureFields('index')); | |||
if ($this->filtersForm === null) { | |||
die('nncncd'); | |||
//TODO delete under code | |||
$options['fields'] = $responseParameters->get('fields'); | |||
$options['entity_class'] = $this->getEntityFqcn(); | |||
$options['entity_name'] = $responseParameters->get('entity')->getName(); | |||
$this->filtersForm = $this->createForm(FiltersFormType::class, null, $options); | |||
} | |||
$responseParameters->set('filters_form', $this->filtersForm); | |||
} | |||
return $responseParameters; | |||
} | |||
public function overrideEntitiesActions(?EntityCollection $entities): void | |||
{ | |||
} | |||
public function overrideGlobalActions(?ActionCollection $actions): void | |||
{ | |||
if ($actions) { | |||
$context = $this->get(AdminContextProvider::class)->getContext(); | |||
$adminUrlGenerator = $this->get(AdminUrlGenerator::class); | |||
foreach ($actions as $i => $action) { | |||
//récriture du bouton 'retour au parent' | |||
if ($action->getName() == 'index_parent') { | |||
$entity = $context->getEntity()->getInstance(); | |||
if ($entity !== null) { | |||
if ($entity->getParent() !== null) { | |||
$url = $adminUrlGenerator | |||
->setController($context->getCrud()->getControllerFqcn()) | |||
->set('entityId', $entity->getParent()->getId()) | |||
->generateUrl(); | |||
$action->setLinkUrl($url); | |||
} | |||
} else { | |||
unset($actions[$i]); | |||
} | |||
} | |||
if ($action->getName() == 'sort') { | |||
$entityId = $context->getRequest()->get('entityId'); | |||
if ($entityId != null) { | |||
$url = $adminUrlGenerator | |||
->setController($context->getCrud()->getControllerFqcn()) | |||
->setAction($action->getName()) | |||
->set('entityId', $entityId) | |||
->generateUrl(); | |||
$action->setLinkUrl($url); | |||
} | |||
} | |||
} | |||
} | |||
} | |||
public function configureCrud(Crud $crud): Crud | |||
{ | |||
$crud = parent::configureCrud($crud); | |||
$this->setMaxResults($crud); | |||
if ($this->isInstanceOf(SortableInterface::class)) { | |||
$crud->setDefaultSort(['position' => 'ASC']); | |||
} | |||
return $crud; | |||
} | |||
public function setMaxResults(Crud $crud): void | |||
{ | |||
$entityClass = $this->getEntityFqcn(); | |||
$paramListMaxResults = 'listMaxResults'; | |||
$paramSessionListMaxResults = $entityClass.'-'.$paramListMaxResults; | |||
$requestListMaxResults = $this->get(RequestStack::class)->getCurrentRequest()->get($paramListMaxResults); | |||
if ($requestListMaxResults) { | |||
$this->get('session')->set($paramSessionListMaxResults, $requestListMaxResults); | |||
} | |||
$maxResults = $this->get('session')->get($paramSessionListMaxResults) ? $this->get('session')->get( | |||
$paramSessionListMaxResults | |||
) : 30; | |||
$crud->setPaginatorPageSize($maxResults); | |||
} | |||
public function getSeoPanel(): ?array | |||
{ | |||
if ($this->isInstanceOf(SeoInterface::class)) { | |||
return [ | |||
FormField::addPanel('seo')->setTemplateName('crud/field/generic'), | |||
TextField::new('metaTitle')->setLabel('Meta Title')->setHelp( | |||
'Affiché dans les résultats de recherche Google' | |||
)->hideOnIndex(), | |||
TextareaField::new('metaDescription')->setLabel('Meta description')->setHelp( | |||
'Affiché dans les résultats de recherche Google' | |||
)->hideOnIndex(), | |||
CollectionField::new('oldUrls') | |||
->setFormTypeOption('entry_type', TextType::class)->setLabel( | |||
'Anciennes urls du document' | |||
)->hideOnIndex(), | |||
]; | |||
} else { | |||
return null; | |||
} | |||
} | |||
public function getConfPanel(): ?array | |||
{ | |||
if ($this->isInstanceOf(DevAliasInterface::class)) { | |||
return [ | |||
FormField::addPanel('configuration')->setTemplateName('crud/field/generic'), | |||
TextField::new('devAlias')->hideOnIndex(), | |||
]; | |||
} else { | |||
return null; | |||
} | |||
} | |||
public function sort(AdminContext $context) | |||
{ | |||
$event = new BeforeCrudActionEvent($context); | |||
$this->get('event_dispatcher')->dispatch($event); | |||
if ($event->isPropagationStopped()) { | |||
return $event->getResponse(); | |||
} | |||
//if (!$this->isGranted(Permission::EA_EXECUTE_ACTION) || !$this->isInstanceOf(SortableInterface::class)) { | |||
if (!$this->isInstanceOf(SortableInterface::class)) { | |||
throw new ForbiddenActionException($context); | |||
} | |||
$fields = FieldCollection::new($this->configureFields(Crud::PAGE_INDEX)); | |||
$filters = $this->get(FilterFactory::class)->create( | |||
$context->getCrud()->getFiltersConfig(), | |||
$fields, | |||
$context->getEntity() | |||
); | |||
$queryBuilder = $this->createIndexQueryBuilder($context->getSearch(), $context->getEntity(), $fields, $filters); | |||
$paginator = $this->get(PaginatorFactory::class)->create($queryBuilder); | |||
$entities = $this->get(EntityFactory::class)->createCollection($context->getEntity(), $paginator->getResults()); | |||
$this->get(EntityFactory::class)->processFieldsForAll($entities, $fields); | |||
$sortableForm = $this->createFormBuilder(array('entities', $paginator->getResults())) | |||
->add( | |||
'entities', | |||
CollectionType::class, | |||
array( | |||
'required' => true, | |||
'allow_add' => true, | |||
'entry_type' => PositionType::class, | |||
) | |||
) | |||
->getForm(); | |||
$entityManager = $this->getDoctrine()->getManagerForClass($this->getEntityFqcn()); | |||
$repository = $entityManager->getRepository($this->getEntityFqcn()); | |||
$sortableForm->handleRequest($context->getRequest()); | |||
if ($sortableForm->isSubmitted() && $sortableForm->isValid()) { | |||
foreach ($sortableForm->get('entities')->getData() as $elm) { | |||
$entityInstance = $repository->find($elm['id']); | |||
$entityDto = $context->getEntity()->newWithInstance($entityInstance); | |||
if (!$entityDto->isAccessible()) { | |||
throw new InsufficientEntityPermissionException($context); | |||
} | |||
$event = new BeforeEntityDeletedEvent($entityInstance); | |||
$this->get('event_dispatcher')->dispatch($event); | |||
$entityInstance = $event->getEntityInstance(); | |||
$entityInstance->setPosition($elm['position']); | |||
$this->updateEntity($entityManager, $entityInstance); | |||
$this->get('event_dispatcher')->dispatch(new AfterEntityUpdatedEvent($entityInstance)); | |||
} | |||
$url = $this->get(AdminUrlGenerator::class) | |||
->setAction(Action::INDEX) | |||
->generateUrl(); | |||
$this->addFlash('success', $this->translatorAdmin->transFlashMessage('sort'), array()); | |||
return $this->redirect($url); | |||
} | |||
$responseParameters = $this->configureResponseParameters( | |||
KeyValueStore::new( | |||
[ | |||
'pageName' => Crud::PAGE_INDEX, | |||
'templatePath' => '@LcSov/adminlte/crud/sort.html.twig', | |||
'entities' => $entities, | |||
'paginator' => $paginator, | |||
'global_actions' => array(), | |||
'batch_actions' => array(), | |||
'filters' => $filters, | |||
'sortable_form' => $sortableForm, | |||
] | |||
) | |||
); | |||
$responseParameters->set('fields', $this->configureFields('index')); | |||
$event = new AfterCrudActionEvent($context, $responseParameters); | |||
$this->get('event_dispatcher')->dispatch($event); | |||
if ($event->isPropagationStopped()) { | |||
return $event->getResponse(); | |||
} | |||
return $responseParameters; | |||
} | |||
public function duplicate(AdminContext $context, EntityComponent $entityComponent, TranslatorAdmin $translatorAdmin, EntityManagerInterface $em) | |||
{ | |||
if (!$this->isGranted( | |||
Permission::EA_EXECUTE_ACTION, | |||
['action' => "duplicate", 'entity' => $context->getEntity()] | |||
)) { | |||
throw new ForbiddenActionException($context); | |||
} | |||
if (!$context->getEntity()->isAccessible()) { | |||
throw new InsufficientEntityPermissionException($context); | |||
} | |||
$newEntity = $entityComponent->duplicateEntity($context->getEntity()->getInstance()); | |||
$em->create($newEntity); | |||
$em->flush(); | |||
$url = $this->get(AdminUrlGenerator::class) | |||
->setAction(Action::EDIT) | |||
->setEntityId($newEntity->getId()) | |||
->generateUrl(); | |||
$this->addFlash('success', $translatorAdmin->transFlashMessage('duplicate'), array()); | |||
return $this->redirect($url); | |||
} | |||
public function createIndexQueryBuilder( | |||
SearchDto $searchDto, | |||
EntityDto $entityDto, | |||
FieldCollection $fields, | |||
FilterCollection $filters | |||
): QueryBuilder { | |||
$queryBuilder = parent::createIndexQueryBuilder( | |||
$searchDto, | |||
$entityDto, | |||
$fields, | |||
$filters | |||
); | |||
//TOdo utiliser les repositoryQuery ? | |||
if ($this->isInstanceOf(TreeInterface::class)) { | |||
$entityId = $searchDto->getRequest()->get('entityId'); | |||
if ($entityId !== null) { | |||
$queryBuilder->andWhereParent('entity', $entityId); | |||
} else { | |||
$queryBuilder->andWhereParentIsNull('entity'); | |||
} | |||
} | |||
$this->filtersForm = $this->createForm( | |||
FiltersFormType::class, | |||
null, | |||
array( | |||
'fields' => $fields, | |||
'entity_dto' => $entityDto, | |||
'entity_class' => $this->getEntityFqcn(), | |||
'entity_name' => $entityDto->getName(), | |||
) | |||
); | |||
$filterManager = $this->get(FilterManager::class); | |||
$this->filtersForm->handleRequest($searchDto->getRequest()); | |||
/*if (($this->filtersForm->isSubmitted() && $this->filtersForm->isValid())) { | |||
}*/ | |||
$filterManager->handleFiltersForm($queryBuilder, $this->filtersForm, $fields, $entityDto); | |||
return $queryBuilder; | |||
} | |||
public function createSortQueryBuilder( | |||
SearchDto $searchDto, | |||
EntityDto $entityDto, | |||
FieldCollection $fields, | |||
FilterCollection $filters | |||
): QueryBuilder { | |||
$queryBuilder = $this->createIndexQueryBuilder($searchDto, $entityDto, $fields, $filters); | |||
return $queryBuilder; | |||
} | |||
public function edit(AdminContext $context) | |||
{ | |||
$response = parent::edit($context);; | |||
// on vide le flash bag si édition en ajax (notification déjà affichée en Javascript) | |||
if ($context->getRequest()->isXmlHttpRequest()) { | |||
$this->get('session')->getFlashBag()->clear(); | |||
} | |||
return $response; | |||
} | |||
public function isInstanceOf(string $interfaceName): bool | |||
{ | |||
return in_array($interfaceName, class_implements($this->getEntityFqcn())); | |||
} | |||
public function getControllerFqcnByInterface(string $interface): string | |||
{ | |||
$context = $this->get(AdminContextProvider::class)->getContext(); | |||
return $context->getCrudControllers()->findCrudFqcnByEntityFqcn( | |||
$this->get(EntityManagerInterface::class)->getEntityName($interface) | |||
); | |||
} | |||
public function updateEntity(EntityManagerInterface $entityManager, $entityInstance): void | |||
{ | |||
$entityManager->update($entityInstance); | |||
$entityManager->flush(); | |||
} | |||
public function persistEntity(EntityManagerInterface $entityManager, $entityInstance): void | |||
{ | |||
$entityManager->create($entityInstance); | |||
$entityManager->flush(); | |||
} | |||
public function configureActions(Actions $actions): Actions | |||
{ | |||
$this->buildIndexActions($actions); | |||
$this->buildEditActions($actions); | |||
$this->buildDetailActions($actions); | |||
$this->buildNewActions($actions); | |||
$this->handleTranslatableEntityActions($actions); | |||
$this->handleSortableEntityActions($actions); | |||
$this->handleTreeEntityActions($actions); | |||
/*$actions->reorder(Crud::PAGE_EDIT, [Action::INDEX, Action::SAVE_AND_RETURN, Action::SAVE_AND_CONTINUE, Action::DELETE]); | |||
$actions->reorder(Crud::PAGE_NEW, [Action::INDEX, Action::SAVE_AND_RETURN, Action::SAVE_AND_ADD_ANOTHER]);*/ | |||
return $actions; | |||
} | |||
public function getDuplicateAction(): Action | |||
{ | |||
$duplicateAction = Action::new( | |||
'duplicate', | |||
$this->get(TranslatorAdmin::class)->transAction('duplicate'), | |||
'fa fa-fw fa-copy' | |||
) | |||
->linkToCrudAction('duplicate') | |||
->setLabel($this->get(TranslatorAdmin::class)->transAction('duplicate')) | |||
->setCssClass('in-dropdown text-info action-confirm'); | |||
return $duplicateAction; | |||
} | |||
public function buildIndexActions(Actions $actions): void | |||
{ | |||
$actions->add(Crud::PAGE_INDEX, $this->getDuplicateAction()); | |||
$this->actionUpdate( | |||
$actions, | |||
Crud::PAGE_INDEX, | |||
Action::NEW, | |||
[ | |||
'icon' => 'plus', | |||
'label' => $this->get(TranslatorAdmin::class)->transAction('create'), | |||
'add_class' => 'btn-sm', | |||
] | |||
); | |||
$this->actionUpdate( | |||
$actions, | |||
Crud::PAGE_INDEX, | |||
Action::EDIT, | |||
[ | |||
'class' => 'btn btn-sm btn-primary', | |||
'icon' => 'edit', | |||
'label' => false, | |||
'html_attributes' => array( | |||
'data-toggle' => 'tooltip', | |||
'title' => $this->get(TranslatorAdmin::class)->transAction('edit'), | |||
), | |||
] | |||
); | |||
$this->actionUpdate( | |||
$actions, | |||
Crud::PAGE_INDEX, | |||
Action::DETAIL, | |||
[ | |||
'icon' => 'eye', | |||
'add_class' => 'btn btn-sm btn-success', | |||
'label' => false, | |||
'html_attributes' => array( | |||
'data-toggle' => 'tooltip', | |||
'title' => $this->get(TranslatorAdmin::class)->transAction('detail'), | |||
), | |||
] | |||
); | |||
$this->actionUpdate( | |||
$actions, | |||
Crud::PAGE_INDEX, | |||
Action::DELETE, | |||
[ | |||
'icon' => 'trash', | |||
'dropdown' => true, | |||
'label' => $this->get(TranslatorAdmin::class)->transAction('delete'), | |||
] | |||
); | |||
$this->actionUpdate( | |||
$actions, | |||
Crud::PAGE_INDEX, | |||
Action::BATCH_DELETE, | |||
[ | |||
'class' => 'btn btn-sm btn-danger', | |||
'icon' => 'trash', | |||
'label' => $this->get(TranslatorAdmin::class)->transAction('delete'), | |||
] | |||
); | |||
} | |||
public function buildEditActions(Actions $actions): void | |||
{ | |||
$actions->add(Crud::PAGE_EDIT, Action::INDEX); | |||
$actions->add(Crud::PAGE_EDIT, Action::DELETE); | |||
$this->actionUpdate( | |||
$actions, | |||
Crud::PAGE_EDIT, | |||
Action::SAVE_AND_RETURN, | |||
[ | |||
'add_class' => 'float-right', | |||
'icon' => 'check', | |||
'label' => $this->get(TranslatorAdmin::class)->transAction('save_and_return'), | |||
] | |||
); | |||
$this->actionUpdate( | |||
$actions, | |||
Crud::PAGE_EDIT, | |||
Action::INDEX, | |||
[ | |||
'icon' => 'chevron-left', | |||
'class' => 'btn btn-link', | |||
'label' => $this->get(TranslatorAdmin::class)->transAction('back_index'), | |||
] | |||
); | |||
$this->actionUpdate( | |||
$actions, | |||
Crud::PAGE_EDIT, | |||
Action::SAVE_AND_CONTINUE, | |||
[ | |||
'class' => 'btn btn-info float-right', | |||
'label' => $this->get(TranslatorAdmin::class)->transAction('save_and_continue'), | |||
] | |||
); | |||
$this->actionUpdate( | |||
$actions, | |||
Crud::PAGE_EDIT, | |||
Action::DELETE, | |||
[ | |||
'icon' => 'trash', | |||
'class' => 'btn btn-outline-danger action-delete', | |||
'label' => $this->get(TranslatorAdmin::class)->transAction('delete'), | |||
] | |||
); | |||
} | |||
public function buildDetailActions(Actions $actions): void | |||
{ | |||
} | |||
public function buildNewActions(Actions $actions): void | |||
{ | |||
$actions->add(Crud::PAGE_NEW, Action::INDEX); | |||
$this->actionUpdate( | |||
$actions, | |||
Crud::PAGE_EDIT, | |||
Action::SAVE_AND_RETURN, | |||
[ | |||
'add_class' => 'float-right', | |||
'icon' => 'check', | |||
'label' => $this->get(TranslatorAdmin::class)->transAction('save_and_return'), | |||
] | |||
); | |||
$this->actionUpdate( | |||
$actions, | |||
Crud::PAGE_EDIT, | |||
Action::INDEX, | |||
[ | |||
'icon' => 'chevron-left', | |||
'class' => 'btn btn-link', | |||
'label' => $this->get(TranslatorAdmin::class)->transAction('back_index'), | |||
] | |||
); | |||
$this->actionUpdate( | |||
$actions, | |||
Crud::PAGE_EDIT, | |||
Action::SAVE_AND_ADD_ANOTHER, | |||
[ | |||
'class' => 'btn btn-info float-right', | |||
'label' => $this->get(TranslatorAdmin::class)->transAction('save_and_add_another'), | |||
] | |||
); | |||
} | |||
public function handleTranslatableEntityActions(Actions $actions): void | |||
{ | |||
if ($this->isInstanceOf(TranslatableInterface::class)) { | |||
$actions->update( | |||
Crud::PAGE_INDEX, | |||
Action::EDIT, | |||
function (Action $action) { | |||
$action->setTemplatePath('@LcSov/adminlte/crud/action/translatable.html.twig'); | |||
return $action; | |||
} | |||
); | |||
} | |||
} | |||
public function handleSortableEntityActions(Actions $actions): void | |||
{ | |||
if ($this->isInstanceOf(SortableInterface::class)) { | |||
$sortAction = Action::new('sort', $this->get(TranslatorAdmin::class)->transAction('sort'), 'fa fa-sort') | |||
->linkToCrudAction('sort') | |||
->setCssClass('btn btn-sm btn-success') | |||
->createAsGlobalAction(); | |||
$actions->add(Crud::PAGE_INDEX, $sortAction); | |||
} | |||
} | |||
public function handleTreeEntityActions(Actions $actions): void | |||
{ | |||
if ($this->isInstanceOf(TreeInterface::class)) { | |||
$indexChildAction = Action::new( | |||
'index_children', | |||
$this->get(TranslatorAdmin::class)->transAction('index_children'), | |||
'fa fa-list' | |||
) | |||
->linkToCrudAction(Action::INDEX) | |||
->setLabel('') | |||
->setHtmlAttributes(array('data-toggle' => 'tooltip', 'title' => 'Afficher les enfants')) | |||
->setTemplatePath('@LcSov/adminlte/crud/action/index_children.html.twig') | |||
->setCssClass('btn btn-sm btn-success'); | |||
$backParentAction = Action::new( | |||
'index_parent', | |||
$this->get(TranslatorAdmin::class)->transAction('index_parent'), | |||
'fa fa-chevron-left' | |||
) | |||
->linkToCrudAction(Action::INDEX) | |||
->setCssClass('btn btn-sm btn-info') | |||
->createAsGlobalAction(); | |||
$actions->add(Crud::PAGE_INDEX, $backParentAction); | |||
$actions->add(Crud::PAGE_INDEX, $indexChildAction); | |||
} | |||
} | |||
public function actionUpdate($actions, $crudActionName, $actionName, array $button): void | |||
{ | |||
if ($actions->getAsDto('actions')->getAction($crudActionName, $actionName)) { | |||
$actions->update( | |||
$crudActionName, | |||
$actionName, | |||
function (Action $action) use ($button) { | |||
if (isset($button['add_class'])) { | |||
$action->addCssClass($button['add_class']); | |||
} | |||
if (isset($button['class'])) { | |||
$action->setCssClass($button['class']); | |||
} | |||
if (isset($button['icon'])) { | |||
$action->setIcon('fa fa-'.$button['icon']); | |||
} | |||
if (isset($button['label'])) { | |||
$action->setLabel($button['label']); | |||
} | |||
if (isset($button['dropdown']) && $button['dropdown']) { | |||
$action->addCssClass('in-dropdown'); | |||
} | |||
if (isset($button['html_attributes']) && $button['html_attributes']) { | |||
$action->setHtmlAttributes($button['html_attributes']); | |||
} | |||
return $action; | |||
} | |||
); | |||
} | |||
} | |||
public function autocompleteFilter(AdminContext $context): JsonResponse | |||
{ | |||
$queryBuilder = $this->createIndexQueryBuilder( | |||
$context->getSearch(), | |||
$context->getEntity(), | |||
FieldCollection::new([]), | |||
FilterCollection::new() | |||
); | |||
$autocompleteContext = $context->getRequest()->get(AssociationField::PARAM_AUTOCOMPLETE_CONTEXT); | |||
/** @var CrudControllerInterface $controller */ | |||
$controller = $this->get(ControllerFactory::class)->getCrudControllerInstance( | |||
$autocompleteContext[EA::CRUD_CONTROLLER_FQCN], | |||
Action::INDEX, | |||
$context->getRequest() | |||
); | |||
/** @var FieldDto $field */ | |||
$field = FieldCollection::new( | |||
$controller->configureFields($autocompleteContext['originatingPage']) | |||
)->getByProperty($autocompleteContext['propertyName']); | |||
$filterManager = $this->get(FilterManager::class); | |||
$filterManager->applyFilter($queryBuilder, $field, $context->getRequest()->query->get('q')); | |||
if ($filterManager->isRelationField($field->getProperty())) { | |||
$queryBuilder->select($autocompleteContext['propertyName']); | |||
} else { | |||
$queryBuilder->select('entity.'.$autocompleteContext['propertyName']); | |||
} | |||
$responses = array(); | |||
foreach ($queryBuilder->getQuery()->getArrayResult() as $result) { | |||
$responses[] = array_values($result)[0]; | |||
} | |||
return JsonResponse::fromJsonString(json_encode($responses)); | |||
} | |||
} | |||
@@ -1,481 +0,0 @@ | |||
<?php | |||
namespace Lc\SovBundle\Controller\Admin; | |||
use Doctrine\ORM\EntityManagerInterface; | |||
use Doctrine\ORM\QueryBuilder; | |||
use EasyCorp\Bundle\EasyAdminBundle\Collection\FieldCollection; | |||
use EasyCorp\Bundle\EasyAdminBundle\Collection\FilterCollection; | |||
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\KeyValueStore; | |||
use EasyCorp\Bundle\EasyAdminBundle\Config\Option\EA; | |||
use EasyCorp\Bundle\EasyAdminBundle\Context\AdminContext; | |||
use EasyCorp\Bundle\EasyAdminBundle\Controller\AbstractCrudController as EaAbstractCrudController; | |||
use EasyCorp\Bundle\EasyAdminBundle\Dto\EntityDto; | |||
use EasyCorp\Bundle\EasyAdminBundle\Dto\SearchDto; | |||
use EasyCorp\Bundle\EasyAdminBundle\Event\AfterCrudActionEvent; | |||
use EasyCorp\Bundle\EasyAdminBundle\Event\AfterEntityUpdatedEvent; | |||
use EasyCorp\Bundle\EasyAdminBundle\Event\BeforeCrudActionEvent; | |||
use EasyCorp\Bundle\EasyAdminBundle\Event\BeforeEntityDeletedEvent; | |||
use EasyCorp\Bundle\EasyAdminBundle\Event\BeforeEntityUpdatedEvent; | |||
use EasyCorp\Bundle\EasyAdminBundle\Exception\ForbiddenActionException; | |||
use EasyCorp\Bundle\EasyAdminBundle\Exception\InsufficientEntityPermissionException; | |||
use EasyCorp\Bundle\EasyAdminBundle\Factory\EntityFactory; | |||
use EasyCorp\Bundle\EasyAdminBundle\Factory\FilterFactory; | |||
use EasyCorp\Bundle\EasyAdminBundle\Factory\PaginatorFactory; | |||
use EasyCorp\Bundle\EasyAdminBundle\Field\FormField; | |||
use EasyCorp\Bundle\EasyAdminBundle\Field\TextareaField; | |||
use EasyCorp\Bundle\EasyAdminBundle\Field\TextField; | |||
use EasyCorp\Bundle\EasyAdminBundle\Router\AdminUrlGenerator; | |||
use EasyCorp\Bundle\EasyAdminBundle\Security\Permission; | |||
use Lc\SovBundle\Doctrine\EntityManager; | |||
use Lc\SovBundle\Doctrine\Extension\DevAliasInterface; | |||
use Lc\SovBundle\Doctrine\Extension\SeoInterface; | |||
use Lc\SovBundle\Doctrine\Extension\SortableInterface; | |||
use Lc\SovBundle\Doctrine\Extension\TranslatableInterface; | |||
use Lc\SovBundle\Doctrine\Extension\TreeInterface; | |||
use Lc\SovBundle\Field\CollectionField; | |||
use Lc\SovBundle\Field\GalleryManagerField; | |||
use Lc\SovBundle\Form\Type\Crud\PositionType; | |||
use Lc\SovBundle\Translation\TranslatorAdmin; | |||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; | |||
use Symfony\Component\Form\Extension\Core\Type\CollectionType; | |||
use Symfony\Component\Form\Extension\Core\Type\TextType; | |||
use Symfony\Component\HttpFoundation\RequestStack; | |||
use Symfony\Component\HttpFoundation\Session\SessionInterface; | |||
use Twig\Environment; | |||
abstract class AbstractCrudController extends EaAbstractCrudController | |||
{ | |||
protected $session; | |||
protected $request; | |||
protected $translatorAdmin; | |||
public function __construct( | |||
SessionInterface $session, | |||
RequestStack $request, | |||
EntityManager $em, | |||
Environment $twig, | |||
TranslatorAdmin $translatorAdmin | |||
) | |||
{ | |||
$this->session = $session; | |||
$this->request = $request; | |||
$this->em = $em; | |||
$this->twig = $twig; | |||
$this->translatorAdmin = $translatorAdmin; | |||
} | |||
public function configureActions(Actions $actions): Actions | |||
{ | |||
/* Translatable */ | |||
if ($this->isInstanceOf(TranslatableInterface::class)) { | |||
$actions->update( | |||
Crud::PAGE_INDEX, | |||
Action::EDIT, | |||
function (Action $action) { | |||
$action->setTemplatePath('@LcSov/adminlte/crud/action/translatable.html.twig'); | |||
return $action; | |||
} | |||
); | |||
} | |||
/* Boutons des actions dans les listes */ | |||
$actionsArray[Crud::PAGE_INDEX] = [ | |||
Action::NEW => [ | |||
'icon' => 'plus', | |||
'label' => $this->translatorAdmin->transAction('create'), | |||
'add_class' => 'btn-sm' | |||
], | |||
Action::EDIT => [ | |||
'class' => 'btn btn-sm btn-primary', | |||
'icon' => 'edit', | |||
'label' => false, | |||
'html_attributes' => array( | |||
'data-toggle' => 'tooltip', | |||
'title' => $this->translatorAdmin->transAction('edit') | |||
) | |||
], | |||
Action::DELETE => [ | |||
'icon' => 'trash', | |||
'dropdown' => true, | |||
'label' => $this->translatorAdmin->transAction('delete') | |||
], | |||
Action::BATCH_DELETE => [ | |||
'class' => 'btn btn-sm btn-danger', | |||
'icon' => 'trash', | |||
'label' => $this->translatorAdmin->transAction('delete') | |||
], | |||
]; | |||
/* Boutons des actions dans l'édition */ | |||
$actionSaveAndReturn = [ | |||
'add_class' => 'float-right', | |||
'icon' => 'check', | |||
'label' => $this->translatorAdmin->transAction('save_and_return') | |||
]; | |||
$actionIndex = [ | |||
'icon' => 'chevron-left', | |||
'class' => 'btn btn-link', | |||
'label' => $this->translatorAdmin->transAction('back_index') | |||
]; | |||
$actionsArray[Crud::PAGE_EDIT] = [ | |||
Action::SAVE_AND_CONTINUE => [ | |||
'class' => 'btn btn-info float-right', | |||
'label' => $this->translatorAdmin->transAction('save_and_continue') | |||
], | |||
Action::DELETE => [ | |||
'icon' => 'trash', | |||
'class' => 'btn btn-outline-danger action-delete', | |||
'label' => $this->translatorAdmin->transAction('delete') | |||
], | |||
Action::SAVE_AND_RETURN => $actionSaveAndReturn, | |||
Action::INDEX => $actionIndex, | |||
]; | |||
$actionsArray[Crud::PAGE_NEW] = [ | |||
Action::SAVE_AND_ADD_ANOTHER => [ | |||
'class' => 'btn btn-info float-right', | |||
'label' => $this->translatorAdmin->transAction('save_and_add_another') | |||
], | |||
Action::SAVE_AND_RETURN => $actionSaveAndReturn, | |||
Action::INDEX => $actionIndex, | |||
]; | |||
$actions->add(Crud::PAGE_EDIT, Action::INDEX); | |||
$actions->add(Crud::PAGE_EDIT, Action::DELETE); | |||
$actions->add(Crud::PAGE_NEW, Action::INDEX); | |||
if ($this->isInstanceOf(SortableInterface::class)) { | |||
$sortAction = Action::new('sort', $this->translatorAdmin->transAction('sort'), 'fa fa-sort') | |||
->linkToCrudAction('sort') | |||
->setCssClass('btn btn-sm btn-success') | |||
->createAsGlobalAction(); | |||
$actions->add(Crud::PAGE_INDEX, $sortAction); | |||
} | |||
if ($this->isInstanceOf(TreeInterface::class)) { | |||
$indexChildAction = Action::new( | |||
'index_children', | |||
$this->translatorAdmin->transAction('index_children'), | |||
'fa fa-list' | |||
) | |||
->linkToCrudAction(Action::INDEX) | |||
->setLabel('') | |||
->setHtmlAttributes(array('data-toggle' => 'tooltip', 'title' => 'Afficher les enfants')) | |||
->setTemplatePath('@LcSov/adminlte/crud/action/index_children.html.twig') | |||
->setCssClass('btn btn-sm btn-success'); | |||
$backParentAction = Action::new( | |||
'index_parent', | |||
$this->translatorAdmin->transAction('index_parent'), | |||
'fa fa-chevron-left' | |||
) | |||
->linkToCrudAction(Action::INDEX) | |||
->setCssClass('btn btn-sm btn-info') | |||
->createAsGlobalAction(); | |||
$actions->add(Crud::PAGE_INDEX, $backParentAction); | |||
$actions->add(Crud::PAGE_INDEX, $indexChildAction); | |||
} | |||
$actions->reorder(Crud::PAGE_EDIT, [Action::INDEX, Action::SAVE_AND_RETURN, Action::SAVE_AND_CONTINUE]); | |||
$actions->reorder(Crud::PAGE_NEW, [Action::INDEX, Action::SAVE_AND_RETURN, Action::SAVE_AND_ADD_ANOTHER]); | |||
foreach ($actionsArray as $crudActionName => $actionsStyle) { | |||
foreach ($actionsStyle as $actionName => $button) { | |||
$actions->update( | |||
$crudActionName, | |||
$actionName, | |||
function (Action $action) use ($button) { | |||
if (isset($button['add_class'])) { | |||
$action->addCssClass($button['add_class']); | |||
} | |||
if (isset($button['class'])) { | |||
$action->setCssClass($button['class']); | |||
} | |||
if (isset($button['icon'])) { | |||
$action->setIcon('fa fa-' . $button['icon']); | |||
} | |||
if (isset($button['label'])) { | |||
$action->setLabel($button['label']); | |||
} | |||
if (isset($button['dropdown']) && $button['dropdown']) { | |||
$action->addCssClass('in-dropdown'); | |||
} | |||
if (isset($button['html_attributes']) && $button['html_attributes']) { | |||
$action->setHtmlAttributes($button['html_attributes']); | |||
} | |||
return $action; | |||
} | |||
); | |||
} | |||
} | |||
return $actions; | |||
} | |||
public function configureResponseParameters(KeyValueStore $responseParameters): KeyValueStore | |||
{ | |||
// fields sur la page index | |||
if (Crud::PAGE_INDEX === $responseParameters->get('pageName')) { | |||
$responseParameters->set('fields', $this->configureFields('index')); | |||
} | |||
return $responseParameters; | |||
} | |||
public function configureCrud(Crud $crud): Crud | |||
{ | |||
$crud = parent::configureCrud($crud); | |||
$this->setMaxResults($crud); | |||
if ($this->isInstanceOf(SortableInterface::class)) { | |||
$crud->setDefaultSort(['position' => 'ASC']); | |||
} | |||
return $crud; | |||
} | |||
public function setMaxResults(Crud $crud) | |||
{ | |||
$entityClass = $this->getEntityFqcn(); | |||
$paramListMaxResults = 'listMaxResults'; | |||
$paramSessionListMaxResults = $entityClass . '-' . $paramListMaxResults; | |||
$requestListMaxResults = $this->request->getCurrentRequest()->get($paramListMaxResults); | |||
if ($requestListMaxResults) { | |||
$this->session->set($paramSessionListMaxResults, $requestListMaxResults); | |||
} | |||
$maxResults = $this->session->get($paramSessionListMaxResults) ? $this->session->get( | |||
$paramSessionListMaxResults | |||
) : 30; | |||
$crud->setPaginatorPageSize($maxResults); | |||
} | |||
public function configureFields(string $pageName): iterable | |||
{ | |||
$seoPanel = $confPanel = array(); | |||
if ($this->isInstanceOf(SortableInterface::class)) { | |||
$seoPanel = [ | |||
FormField::addPanel('seo')->setTemplateName('crud/field/generic'), | |||
TextField::new('metaTitle')->setLabel('Meta Title')->setHelp( | |||
'Affiché dans les résultats de recherche Google' | |||
)->hideOnIndex(), | |||
TextareaField::new('metaDescription')->setLabel('Meta description')->setHelp( | |||
'Affiché dans les résultats de recherche Google' | |||
)->hideOnIndex(), | |||
CollectionField::new('oldUrls') | |||
->setFormTypeOption('entry_type', TextType::class)->setLabel( | |||
'Anciennes urls du document' | |||
)->hideOnIndex(), | |||
]; | |||
} | |||
if ($this->isInstanceOf(DevAliasInterface::class)) { | |||
$confPanel = [ | |||
FormField::addPanel('configuration')->setTemplateName('crud/field/generic'), | |||
TextField::new('devAlias')->hideOnIndex(), | |||
]; | |||
} | |||
return array_merge($seoPanel, $confPanel); | |||
} | |||
public function sort(AdminContext $context) | |||
{ | |||
$event = new BeforeCrudActionEvent($context); | |||
$this->get('event_dispatcher')->dispatch($event); | |||
if ($event->isPropagationStopped()) { | |||
return $event->getResponse(); | |||
} | |||
if (!$this->isGranted(Permission::EA_EXECUTE_ACTION) || !$this->isInstanceOf(SortableInterface::class)) { | |||
throw new ForbiddenActionException($context); | |||
} | |||
$fields = FieldCollection::new($this->configureFields(Crud::PAGE_INDEX)); | |||
$filters = $this->get(FilterFactory::class)->create( | |||
$context->getCrud()->getFiltersConfig(), | |||
$fields, | |||
$context->getEntity() | |||
); | |||
$queryBuilder = $this->createIndexQueryBuilder($context->getSearch(), $context->getEntity(), $fields, $filters); | |||
$paginator = $this->get(PaginatorFactory::class)->create($queryBuilder); | |||
$entities = $this->get(EntityFactory::class)->createCollection($context->getEntity(), $paginator->getResults()); | |||
$this->get(EntityFactory::class)->processFieldsForAll($entities, $fields); | |||
$sortableForm = $this->createFormBuilder(array('entities', $paginator->getResults())) | |||
->add( | |||
'entities', | |||
CollectionType::class, | |||
array( | |||
'required' => true, | |||
'allow_add' => true, | |||
'entry_type' => PositionType::class, | |||
) | |||
) | |||
->getForm(); | |||
$entityManager = $this->getDoctrine()->getManagerForClass($this->getEntityFqcn()); | |||
$repository = $entityManager->getRepository($this->getEntityFqcn()); | |||
$sortableForm->handleRequest($context->getRequest()); | |||
if ($sortableForm->isSubmitted() && $sortableForm->isValid()) { | |||
foreach ($sortableForm->get('entities')->getData() as $elm) { | |||
$entityInstance = $repository->find($elm['id']); | |||
$entityDto = $context->getEntity()->newWithInstance($entityInstance); | |||
if (!$entityDto->isAccessible()) { | |||
throw new InsufficientEntityPermissionException($context); | |||
} | |||
$event = new BeforeEntityDeletedEvent($entityInstance); | |||
$this->get('event_dispatcher')->dispatch($event); | |||
$entityInstance = $event->getEntityInstance(); | |||
$entityInstance->setPosition($elm['position']); | |||
$this->updateEntity($entityManager, $entityInstance); | |||
$this->get('event_dispatcher')->dispatch(new AfterEntityUpdatedEvent($entityInstance)); | |||
} | |||
$url = $this->get(AdminUrlGenerator::class) | |||
->setAction(Action::INDEX) | |||
->generateUrl(); | |||
$this->addFlash('success', $this->translatorAdmin->transFlashMessage('sort'), array()); | |||
return $this->redirect($url); | |||
} | |||
$responseParameters = $this->configureResponseParameters( | |||
KeyValueStore::new( | |||
[ | |||
'pageName' => Crud::PAGE_INDEX, | |||
'templatePath' => '@LcSov/adminlte/crud/sort.html.twig', | |||
'entities' => $entities, | |||
'paginator' => $paginator, | |||
'global_actions' => array(), | |||
'batch_actions' => array(), | |||
'filters' => $filters, | |||
'sortable_form' => $sortableForm, | |||
] | |||
) | |||
); | |||
$responseParameters->set('fields', $this->configureFields('index')); | |||
$event = new AfterCrudActionEvent($context, $responseParameters); | |||
$this->get('event_dispatcher')->dispatch($event); | |||
if ($event->isPropagationStopped()) { | |||
return $event->getResponse(); | |||
} | |||
return $responseParameters; | |||
} | |||
public function createIndexQueryBuilder( | |||
SearchDto $searchDto, | |||
EntityDto $entityDto, | |||
FieldCollection $fields, | |||
FilterCollection $filters | |||
): QueryBuilder | |||
{ | |||
$queryBuilder = parent::createIndexQueryBuilder( | |||
$searchDto, | |||
$entityDto, | |||
$fields, | |||
$filters | |||
); | |||
if ($this->isInstanceOf(TreeInterface::class)) { | |||
$entityId = $searchDto->getRequest()->get('entityId'); | |||
if ($entityId !== null) { | |||
$queryBuilder->andWhere('entity.parent = :entityId'); | |||
$queryBuilder->setParameter('entityId', $searchDto->getRequest()->get('entityId')); | |||
} else { | |||
$queryBuilder->andWhere('entity.parent IS NULL'); | |||
} | |||
} | |||
return $queryBuilder; | |||
} | |||
public function createSortQueryBuilder( | |||
SearchDto $searchDto, | |||
EntityDto $entityDto, | |||
FieldCollection $fields, | |||
FilterCollection $filters | |||
): QueryBuilder | |||
{ | |||
$queryBuilder = parent::createIndexQueryBuilder( | |||
$searchDto, | |||
$entityDto, | |||
$fields, | |||
$filters | |||
); | |||
if ($this->isInstanceOf(TreeInterface::class)) { | |||
$entityId = $searchDto->getRequest()->get('entityId'); | |||
if ($entityId !== null) { | |||
$queryBuilder->andWhere('entity.parent = :entityId'); | |||
$queryBuilder->setParameter('entityId', $searchDto->getRequest()->get('entityId')); | |||
} else { | |||
$queryBuilder->andWhere('entity.parent IS NULL'); | |||
} | |||
} | |||
return $queryBuilder; | |||
} | |||
public function edit(AdminContext $context) | |||
{ | |||
$response = parent::edit($context);; | |||
// on vide le flash bag si édition en ajax (notification déjà affichée en Javascript) | |||
if ($context->getRequest()->isXmlHttpRequest()) { | |||
$this->session->getFlashBag()->clear(); | |||
} | |||
return $response; | |||
} | |||
public function isInstanceOf(string $interfaceName): bool | |||
{ | |||
return in_array($interfaceName, class_implements($this->getEntityFqcn())); | |||
} | |||
public function updateEntity(EntityManagerInterface $entityManager, $entityInstance): void | |||
{ | |||
$entityManager->update($entityInstance); | |||
$entityManager->flush(); | |||
} | |||
public function persistEntity(EntityManagerInterface $entityManager, $entityInstance): void | |||
{ | |||
$entityManager->create($entityInstance); | |||
$entityManager->flush(); | |||
} | |||
} | |||
@@ -1,20 +0,0 @@ | |||
<?php | |||
namespace Lc\SovBundle\Controller\Admin; | |||
use EasyCorp\Bundle\EasyAdminBundle\Config\Action; | |||
use EasyCorp\Bundle\EasyAdminBundle\Config\Actions; | |||
use EasyCorp\Bundle\EasyAdminBundle\Config\Crud; | |||
use EasyCorp\Bundle\EasyAdminBundle\Field\TextField; | |||
abstract class UserCrudController extends AbstractCrudController | |||
{ | |||
public function configureFields(string $pageName): iterable | |||
{ | |||
return [ | |||
TextField::new('email') | |||
]; | |||
} | |||
} |
@@ -1,6 +1,6 @@ | |||
<?php | |||
namespace Lc\SovBundle\Controller\Admin; | |||
namespace Lc\SovBundle\Controller\Dashboard; | |||
use EasyCorp\Bundle\EasyAdminBundle\Config\Assets; | |||
use EasyCorp\Bundle\EasyAdminBundle\Config\Crud; | |||
@@ -13,8 +13,9 @@ use Symfony\Component\Security\Core\User\UserInterface; | |||
use Symfony\Component\HttpFoundation\Response; | |||
use Symfony\Component\Routing\Annotation\Route; | |||
class DashboardController extends AbstractDashboardController | |||
class DashboardAdminController extends AbstractDashboardController | |||
{ | |||
public function index(): Response | |||
{ | |||
return $this->render('@LcSov/adminlte/dashboard.html.twig'); | |||
@@ -26,7 +27,7 @@ class DashboardController extends AbstractDashboardController | |||
// the name visible to end users | |||
->setTitle('LA CLIC !') | |||
// you can include HTML contents too (e.g. to link to an image) | |||
->setTitle('<img src="assets/img/laclic.png" width="100px">') | |||
->setTitle('<img src="assets/img/'.$this->get('parameter_bag')->get('app.admin.logo').'" width="100px">') | |||
// the path defined in this method is passed to the Twig asset() function | |||
->setFaviconPath('favicon.svg') | |||
// the domain used by default is 'messages' | |||
@@ -37,12 +38,14 @@ class DashboardController extends AbstractDashboardController | |||
{ | |||
$assets = parent::configureAssets(); | |||
$assets->addWebpackEncoreEntry('adminlte-common'); | |||
$assets->addWebpackEncoreEntry('adminlte-plugins'); | |||
$assets->addWebpackEncoreEntry('adminlte-index'); | |||
$assets->addWebpackEncoreEntry('adminlte-form'); | |||
$assets->addWebpackEncoreEntry('adminlte-sort'); | |||
$assets->addWebpackEncoreEntry('adminlte-field-collection'); | |||
$assets->addWebpackEncoreEntry('adminlte-field-filemanager'); | |||
$assets->addWebpackEncoreEntry('adminlte-main'); | |||
$assets->addWebpackEncoreEntry('sov-reminder'); | |||
return $assets; | |||
} | |||
@@ -54,7 +57,7 @@ class DashboardController extends AbstractDashboardController | |||
// if you prefer to create the user menu from scratch, use: return UserMenu::new()->... | |||
return parent::configureUserMenu($user) | |||
// use the given $user object to get the user name | |||
->setName($user->getName()) | |||
->setName($user->getFirstName()) | |||
// use this method if you don't want to display the name of the user | |||
//->displayUserName(false) | |||
->displayUserAvatar(false) | |||
@@ -82,17 +85,16 @@ class DashboardController extends AbstractDashboardController | |||
'main_menu' => '@LcSov/adminlte/block/menu.html.twig', | |||
'crud/index' => '@LcSov/adminlte/crud/index.html.twig', | |||
'crud/paginator' => '@LcSov/adminlte/crud/paginator.html.twig', | |||
'crud/edit' => '@LcSov/adminlte/crud/edit.html.twig', | |||
'crud/new' => '@LcSov/adminlte/crud/new.html.twig', | |||
'crud/edit' => '@LcSov/adminlte/crud/form.html.twig', | |||
'crud/new' => '@LcSov/adminlte/crud/form.html.twig', | |||
'flash_messages' => '@LcSov/adminlte/block/flash_messages.html.twig', | |||
] | |||
) | |||
->setFormThemes( | |||
[ | |||
'@LcSov/adminlte/crud/form_theme.html.twig', | |||
'@FOSCKEditor/Form/ckeditor_widget.html.twig' | |||
//'@FOSCKEditor/Form/ckeditor_widget.html.twig' | |||
] | |||
); | |||
} | |||
} |
@@ -0,0 +1,38 @@ | |||
<?php | |||
namespace Lc\SovBundle\Controller\Newsletter; | |||
use EasyCorp\Bundle\EasyAdminBundle\Field\FormField; | |||
use EasyCorp\Bundle\EasyAdminBundle\Field\TextField; | |||
use Lc\SovBundle\Container\Newsletter\NewsletterContainer; | |||
use Lc\SovBundle\Controller\AbstractAdminController; | |||
use Lc\SovBundle\Factory\Newsletter\NewsletterFactory; | |||
use Lc\SovBundle\Field\BooleanField; | |||
use Lc\SovBundle\Field\CKEditorField; | |||
use Lc\SovBundle\Field\StatusField; | |||
abstract class NewsletterAdminController extends AbstractAdminController | |||
{ | |||
public function configureFields(string $pageName): iterable | |||
{ | |||
return array_merge( | |||
[ | |||
FormField::addPanel('general'), | |||
TextField::new('title'), | |||
BooleanField::new('isMain') | |||
->setCustomOption('toggle_label', 'Principale'), | |||
CKEditorField::new('description') | |||
->hideOnIndex(), | |||
StatusField::new('status'), | |||
], | |||
$this->getSeoPanel(), | |||
$this->getConfPanel() | |||
); | |||
} | |||
public function createEntity(string $entityFqcn) | |||
{ | |||
return $this->get(NewsletterContainer::class)->getFactory()->create(); | |||
} | |||
} |
@@ -0,0 +1,154 @@ | |||
<?php | |||
namespace Lc\SovBundle\Controller\Reminder; | |||
use Doctrine\ORM\EntityManagerInterface; | |||
use Lc\CaracoleBundle\Resolver\MerchantResolver; | |||
use Lc\CaracoleBundle\Resolver\SectionResolver; | |||
use Lc\SovBundle\Container\Reminder\ReminderContainer; | |||
use Lc\SovBundle\Factory\Reminder\ReminderFactory; | |||
use Lc\SovBundle\Form\Reminder\ReminderAdminFormType; | |||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; | |||
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface; | |||
use Symfony\Component\Form\FormFactoryInterface; | |||
use Symfony\Component\HttpFoundation\JsonResponse; | |||
use Symfony\Component\HttpFoundation\Request; | |||
use Symfony\Component\HttpFoundation\Response; | |||
use Symfony\Component\Routing\Generator\UrlGeneratorInterface; | |||
use Symfony\Component\Routing\Annotation\Route; | |||
class ReminderAdminController extends AbstractController | |||
{ | |||
protected EntityManagerInterface $entityManager; | |||
protected ReminderContainer $reminderContainer; | |||
protected FormFactoryInterface $formFactory; | |||
protected UrlGeneratorInterface $urlGenerator; | |||
protected MerchantResolver $merchantResolver; | |||
protected SectionResolver $sectionResolver; | |||
protected ParameterBagInterface $parameterBag; | |||
public function __construct( | |||
EntityManagerInterface $entityManager, | |||
ReminderContainer $reminderContainer, | |||
FormFactoryInterface $formFactory, | |||
UrlGeneratorInterface $urlGenerator, | |||
ParameterBagInterface $parameterBag | |||
) { | |||
$this->entityManager = $entityManager; | |||
$this->reminderContainer = $reminderContainer; | |||
$this->formFactory = $formFactory; | |||
$this->urlGenerator = $urlGenerator; | |||
$this->parameterBag = $parameterBag; | |||
} | |||
/** | |||
* @Route("/admin/reminder/modal", name="sov_admin_reminder_render_modal") | |||
*/ | |||
public function renderModal(Request $request): Response | |||
{ | |||
$id = $request->get('id'); | |||
if($id) { | |||
$reminder = $this->reminderContainer->getRepositoryQuery()->getRepository()->find($id); | |||
$action = $this->urlGenerator->generate( | |||
$this->parameterBag->get('app.reminder.route_edit'), | |||
['id' => $id] | |||
); | |||
} | |||
else { | |||
$crudAction = $request->get('crudAction'); | |||
$crudControllerFqcn = $request->get('crudControllerFqcn'); | |||
$entityId = $request->get('entityId') ? $request->get('entityId') : null ; | |||
$reminder = $this->createEntity($crudAction, $crudControllerFqcn, $entityId); | |||
$action = $this->urlGenerator->generate( | |||
$this->parameterBag->get('app.reminder.route_new') | |||
); | |||
} | |||
$form = $this->formFactory->create( | |||
ReminderAdminFormType::class, | |||
$reminder, | |||
[ | |||
'action' => $action | |||
] | |||
); | |||
return $this->render( | |||
'@LcSov/admin/reminder/form_modal.html.twig', | |||
[ | |||
'form_reminder' => $form->createView() | |||
] | |||
); | |||
} | |||
/** | |||
* @Route("/admin/reminder/new", name="sov_admin_reminder_new") | |||
*/ | |||
public function new(Request $request) | |||
{ | |||
$reminder = $this->createEntity(); | |||
$form = $this->formFactory->create(ReminderAdminFormType::class, $reminder); | |||
$form->handleRequest($request); | |||
if ($form->isSubmitted() && $form->isValid()) { | |||
$reminder = $form->getData(); | |||
$this->entityManager->persist($reminder); | |||
$this->entityManager->flush(); | |||
$this->addFlash('success', 'Le pense-bête a bien été ajouté'); | |||
} | |||
return $this->redirect($request->headers->get('referer')); | |||
} | |||
/** | |||
* @Route("/admin/reminder/edit/{id}", name="sov_admin_reminder_edit") | |||
*/ | |||
public function edit(Request $request) | |||
{ | |||
$id = $request->get('id'); | |||
$reminder = $this->reminderContainer->getRepositoryQuery()->getRepository()->find($id); | |||
$form = $this->formFactory->create(ReminderAdminFormType::class, $reminder); | |||
$form->handleRequest($request); | |||
if ($form->isSubmitted() && $form->isValid()) { | |||
$reminder = $form->getData(); | |||
$this->entityManager->update($reminder); | |||
$this->entityManager->flush(); | |||
$this->addFlash('success', 'Le pense-bête a bien été mis à jour'); | |||
} | |||
return $this->redirect($request->headers->get('referer')); | |||
} | |||
/** | |||
* @Route("/admin/reminder/done", name="sov_admin_reminder_done") | |||
*/ | |||
public function done(Request $request): JsonResponse | |||
{ | |||
$id = $request->get('id'); | |||
$reminder = $this->reminderContainer->getRepositoryQuery()->getRepository()->find($id); | |||
$done = $request->get('done'); | |||
if($done == 'true') { | |||
$reminder->setDone(true); | |||
} | |||
else { | |||
$reminder->setDone(false); | |||
} | |||
$this->entityManager->update($reminder); | |||
$this->entityManager->flush(); | |||
return new JsonResponse(['success' => true]); | |||
} | |||
public function createEntity(string $crudAction = null, string $crudControllerFqcn = null, int $entityId = null) | |||
{ | |||
$factory = new ReminderFactory(); | |||
return $factory->create($crudAction, $crudControllerFqcn, $entityId); | |||
} | |||
} |
@@ -1,19 +1,21 @@ | |||
<?php | |||
namespace Lc\SovBundle\Controller\Admin; | |||
namespace Lc\SovBundle\Controller\Security; | |||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; | |||
use Symfony\Component\HttpFoundation\Response; | |||
use Symfony\Component\Routing\Annotation\Route; | |||
use Symfony\Component\Security\Http\Authentication\AuthenticationUtils; | |||
class SecurityController extends AbstractController | |||
class SecurityAdminController extends AbstractController | |||
{ | |||
/** | |||
* @Route("/login", name="sov_login") | |||
*/ | |||
public function login(AuthenticationUtils $authenticationUtils): Response | |||
{ | |||
if ($this->getUser()) { | |||
return $this->redirectToRoute('admin_dashboard'); | |||
return $this->redirectToRoute('app_admin_dashboard'); | |||
} | |||
// get the login error if there is one | |||
@@ -37,14 +39,14 @@ class SecurityController extends AbstractController | |||
// the title visible above the login form (define this option only if you are | |||
// rendering the login template in a regular Symfony controller; when rendering | |||
// it from an EasyAdmin Dashboard this is automatically set as the Dashboard title) | |||
'page_title' => '<img src="assets/img/laclic.png" >', | |||
'page_title' => '<img src="assets/img/'.$this->get('parameter_bag')->get('app.admin.logo').'" >', | |||
// the string used to generate the CSRF token. If you don't define | |||
// this parameter, the login form won't include a CSRF token | |||
'csrf_token_intention' => 'authenticate', | |||
// the URL users are redirected to after the login (default: '/admin') | |||
'target_path' => $this->generateUrl('admin_dashboard'), | |||
'target_path' => $this->generateUrl('app_admin_dashboard'), | |||
// the label displayed for the username form field (the |trans filter is applied to it) | |||
'username_label' => 'Your username', | |||
@@ -63,7 +65,9 @@ class SecurityController extends AbstractController | |||
]); | |||
} | |||
/** | |||
* @Route("/logout", name="sov_logout") | |||
*/ | |||
public function logout() | |||
{ | |||
throw new \LogicException('This method can be blank - it will be intercepted by the logout key on your firewall.'); |
@@ -0,0 +1,54 @@ | |||
<?php | |||
namespace Lc\SovBundle\Controller\Setting; | |||
use Doctrine\ORM\EntityManagerInterface; | |||
use Lc\SovBundle\Container\Setting\SiteSettingContainer; | |||
use Lc\SovBundle\Container\Site\SiteContainer; | |||
use Lc\SovBundle\Definition\SiteSettingDefinitionInterface; | |||
use Lc\SovBundle\Form\Setting\SiteSettingsFormType; | |||
use Lc\SovBundle\Repository\Setting\SiteSettingRepository; | |||
use Lc\SovBundle\Repository\Site\SiteRepository; | |||
use Lc\SovBundle\Translation\TranslatorAdmin; | |||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; | |||
use Symfony\Component\HttpFoundation\Request; | |||
use Symfony\Component\Routing\Annotation\Route; | |||
class SettingAdminController extends AbstractController | |||
{ | |||
protected EntityManagerInterface $entityManager; | |||
public function __construct(EntityManagerInterface $entityManager) | |||
{ | |||
$this->entityManager = $entityManager; | |||
} | |||
/** | |||
* @Route("/admin/setting/site", name="sov_admin_setting_site") | |||
*/ | |||
public function manageGlobal(Request $request, EntityManagerInterface $entityManager) | |||
{ | |||
$site = $this->get(SiteContainer::class)->getStore()->getOneByDevAlias('default') ; | |||
$form = $this->createForm(SiteSettingsFormType::class, $site); | |||
$form->handleRequest($request); | |||
if ($form->isSubmitted() && $form->isValid()) { | |||
$entityManager->update($site); | |||
$entityManager->flush(); | |||
$this->addFlash('success', $this->get(TranslatorAdmin::class)->transFlashMessage('settings_saved')); | |||
} | |||
return $this->render( | |||
'@LcSov/admin/setting/edit_site.html.twig' , | |||
[ | |||
'setting_definition' => $this->get(SiteSettingContainer::class)->getDefinition(), | |||
'form' => $form->createView() | |||
] | |||
); | |||
} | |||
} |
@@ -0,0 +1,42 @@ | |||
<?php | |||
namespace Lc\SovBundle\Controller\Site; | |||
use EasyCorp\Bundle\EasyAdminBundle\Field\DateField; | |||
use EasyCorp\Bundle\EasyAdminBundle\Field\FormField; | |||
use EasyCorp\Bundle\EasyAdminBundle\Field\NumberField; | |||
use EasyCorp\Bundle\EasyAdminBundle\Field\TextField; | |||
use Lc\SovBundle\Container\Site\NewsContainer; | |||
use Lc\SovBundle\Controller\AbstractAdminController; | |||
use Lc\SovBundle\Factory\Site\NewsFactory; | |||
use Lc\SovBundle\Field\CKEditorField; | |||
use Lc\SovBundle\Field\StatusField; | |||
abstract class NewsAdminController extends AbstractAdminController | |||
{ | |||
public function configureFields(string $pageName): iterable | |||
{ | |||
$panel = parent::configureFields($pageName); | |||
return array_merge( | |||
[ | |||
FormField::addPanel('general'), | |||
TextField::new('title'), | |||
DateField::new('date') | |||
->setFormat('d/MM/y'), | |||
NumberField::new('position') | |||
->hideOnIndex() | |||
->hideOnForm(), | |||
CKEditorField::new('description'), | |||
StatusField::new('status'), | |||
], | |||
$panel | |||
); | |||
} | |||
public function createEntity(string $entityFqcn) | |||
{ | |||
return $this->get(NewsContainer::class)->getFactory()->create(); | |||
} | |||
} |
@@ -0,0 +1,40 @@ | |||
<?php | |||
namespace Lc\SovBundle\Controller\Site; | |||
use EasyCorp\Bundle\EasyAdminBundle\Field\FormField; | |||
use EasyCorp\Bundle\EasyAdminBundle\Field\NumberField; | |||
use EasyCorp\Bundle\EasyAdminBundle\Field\TextField; | |||
use Lc\SovBundle\Container\Site\PageContainer; | |||
use Lc\SovBundle\Controller\AbstractAdminController; | |||
use Lc\SovBundle\Factory\Site\PageFactory; | |||
use Lc\SovBundle\Field\CKEditorField; | |||
use Lc\SovBundle\Field\StatusField; | |||
abstract class PageAdminController extends AbstractAdminController | |||
{ | |||
public function configureFields(string $pageName): iterable | |||
{ | |||
$panel = parent::configureFields($pageName); | |||
return array_merge( | |||
[ | |||
FormField::addPanel('general'), | |||
TextField::new('title'), | |||
NumberField::new('position') | |||
->hideOnIndex() | |||
->hideOnForm(), | |||
CKEditorField::new('description'), | |||
StatusField::new('status'), | |||
], | |||
$panel | |||
); | |||
} | |||
public function createEntity(string $entityFqcn) | |||
{ | |||
return $this->get(PageContainer::class)->getFactory()->create(); | |||
} | |||
} |
@@ -0,0 +1,188 @@ | |||
<?php | |||
namespace Lc\SovBundle\Controller\Ticket; | |||
use Doctrine\ORM\EntityManagerInterface; | |||
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\Context\AdminContext; | |||
use EasyCorp\Bundle\EasyAdminBundle\Field\AssociationField; | |||
use EasyCorp\Bundle\EasyAdminBundle\Field\ChoiceField; | |||
use EasyCorp\Bundle\EasyAdminBundle\Field\DateField; | |||
use EasyCorp\Bundle\EasyAdminBundle\Field\IntegerField; | |||
use EasyCorp\Bundle\EasyAdminBundle\Field\TextField; | |||
use EasyCorp\Bundle\EasyAdminBundle\Router\AdminUrlGenerator; | |||
use Lc\SovBundle\Container\Ticket\TicketContainer; | |||
use Lc\SovBundle\Factory\Ticket\TicketFactory; | |||
use Lc\SovBundle\Factory\Ticket\TicketFactoryInterface; | |||
use Lc\SovBundle\Factory\Ticket\TicketMessageFactory; | |||
use Lc\SovBundle\Factory\Ticket\TicketMessageFactoryInterface; | |||
use Lc\SovBundle\Form\Ticket\TicketFormType; | |||
use Lc\SovBundle\Form\Ticket\TicketMessageFormType; | |||
use Lc\SovBundle\Form\Ticket\TicketStatusType; | |||
use Lc\SovBundle\Model\Ticket\TicketInterface; | |||
use Lc\SovBundle\Controller\AbstractAdminController; | |||
use Lc\SovBundle\Model\Ticket\TicketModel; | |||
use Lc\SovBundle\Translation\TranslatorAdmin; | |||
use Symfony\Component\HttpFoundation\JsonResponse; | |||
use Symfony\Component\HttpFoundation\RequestStack; | |||
class TicketAdminController extends AbstractAdminController | |||
{ | |||
public static function getEntityFqcn(): string | |||
{ | |||
return TicketInterface::class; | |||
} | |||
public function createEntity(string $entityFqcn) | |||
{ | |||
return $this->get(TicketContainer::class)->getFactory()->create(); | |||
} | |||
public function configureAssets(Assets $assets): Assets | |||
{ | |||
$assets = parent::configureAssets($assets); | |||
$assets->addWebpackEncoreEntry('sov-ticket'); | |||
return $assets; | |||
} | |||
public function configureFields(string $pageName): iterable | |||
{ | |||
$translatorAdmin = $this->get(TranslatorAdmin::class); | |||
return [ | |||
IntegerField::new('id') | |||
->hideOnForm(), | |||
DateField::new('createdAt')->setFormat('short') | |||
->hideOnForm(), | |||
TextField::new('visitorFirstName') | |||
->setTemplatePath('@LcSov/admin/ticket/field/username.html.twig') | |||
->hideOnForm(), | |||
TextField::new('visitorEmail') | |||
->setTemplatePath('@LcSov/admin/ticket/field/email.html.twig') | |||
->hideOnForm(), | |||
AssociationField::new('user') | |||
->hideOnIndex(), | |||
TextField::new('subject'), | |||
TextField::new('lastMessage') | |||
->setTemplatePath('@LcSov/admin/ticket/field/lastmessage.html.twig') | |||
->hideOnForm(), | |||
ChoiceField::new('type') | |||
->autocomplete() | |||
->setChoices( | |||
$translatorAdmin->transChoices($this->get(TicketContainer::class)->getSolver()->getTypeChoices(), 'Ticket', 'type') | |||
), | |||
ChoiceField::new('status') | |||
->autocomplete() | |||
->setChoices( | |||
$translatorAdmin->transChoices($this->get(TicketContainer::class)->getSolver()->getStatusChoices(), 'Ticket', 'status') | |||
) | |||
->setTemplatePath('@LcSov/admin/ticket/field/status.html.twig') | |||
->hideOnForm(), | |||
]; | |||
} | |||
public function configureActions(Actions $actions): Actions | |||
{ | |||
$actions | |||
->add(Crud::PAGE_INDEX, Action::DETAIL) | |||
->remove(Crud::PAGE_INDEX, Action::EDIT); | |||
return parent::configureActions($actions); | |||
} | |||
public function new(AdminContext $context) | |||
{ | |||
$adminUrlGenerator = $this->get(AdminUrlGenerator::class); | |||
$ticket = $this->createEntity($context->getEntity()->getFqcn()); | |||
$form = $this->createForm(TicketFormType::class, $ticket); | |||
$form->handleRequest($context->getRequest()); | |||
if ($form->isSubmitted() && $form->isValid()) { | |||
$ticket = $form->getData(); | |||
$this->get(EntityManagerInterface::class)->create($ticket); | |||
$this->get(EntityManagerInterface::class)->flush(); | |||
$url = $adminUrlGenerator | |||
->setAction('index') | |||
->generateUrl(); | |||
return $this->redirect($url); | |||
} | |||
return $this->render( | |||
'@LcSov/admin/ticket/new.html.twig', | |||
[ | |||
'form' => $form->createView(), | |||
] | |||
); | |||
} | |||
public function detail(AdminContext $context) | |||
{ | |||
$adminUrlGenerator = $this->get(AdminUrlGenerator::class); | |||
$ticket = $context->getEntity()->getInstance(); | |||
$url = $adminUrlGenerator | |||
->setAction('ticketStatusAction') | |||
->generateUrl(); | |||
$formTicketStatus = $this->createForm( | |||
TicketStatusType::class, | |||
$ticket, | |||
[ | |||
'action' => $url, | |||
'method' => 'POST', | |||
] | |||
); | |||
$ticketMessage = $this->get(TicketContainer::class)->getFactory()->create(); | |||
$formAddTicketMessage = $this->createForm(TicketMessageFormType::class, $ticketMessage); | |||
$formAddTicketMessage->handleRequest($this->get(RequestStack::class)->getMainRequest()); | |||
if ($formAddTicketMessage->isSubmitted() && $formAddTicketMessage->isValid()) { | |||
$ticketMessage = $formAddTicketMessage->getData(); | |||
$ticketMessage->setTicket($ticket); | |||
$ticketMessage->setAnswerByAdmin(true); | |||
$this->get(EntityManagerInterface::class)->create($ticketMessage); | |||
$this->get(EntityManagerInterface::class)->flush(); | |||
} | |||
return $this->render( | |||
'@LcSov/admin/ticket/detail.html.twig', | |||
[ | |||
'form_ticket_status' => $formTicketStatus->createView(), | |||
'form_add_ticket_message' => $formAddTicketMessage->createView(), | |||
'ticket' => $ticket, | |||
] | |||
); | |||
} | |||
public function ticketStatusAction() | |||
{ | |||
$request = $this->get('request')->getMasterRequest(); | |||
$ticket = $request->attributes->get('easyadmin_context')->getEntity()->getInstance(); | |||
$formTicketStatusForm = $this->createForm(TicketStatusType::class, $ticket); | |||
$formTicketStatusForm->handleRequest($request); | |||
$success = false; | |||
if ($formTicketStatusForm->isSubmitted() && $formTicketStatusForm->isValid()) { | |||
$this->get('em')->persist($ticket); | |||
$this->get('em')->flush(); | |||
$success = true; | |||
} | |||
return new JsonResponse(['success' => $success]); | |||
} | |||
} |
@@ -1,28 +1,31 @@ | |||
<?php | |||
namespace Lc\SovBundle\Controller\Admin; | |||
namespace Lc\SovBundle\Controller\User; | |||
use EasyCorp\Bundle\EasyAdminBundle\Dto\EntityDto; | |||
use EasyCorp\Bundle\EasyAdminBundle\Provider\AdminContextProvider; | |||
use Doctrine\ORM\EntityManagerInterface; | |||
use Lc\SovBundle\Doctrine\EntityManager; | |||
use Lc\SovBundle\Form\Type\User\ChangePasswordFormType; | |||
use Lc\SovBundle\Form\Type\User\ProfileFormType; | |||
use Lc\SovBundle\Form\User\ChangePasswordFormType; | |||
use Lc\SovBundle\Form\User\ProfileFormType; | |||
use Lc\SovBundle\Model\User\User; | |||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; | |||
use Symfony\Component\HttpFoundation\Request; | |||
use Symfony\Component\HttpFoundation\Response; | |||
use Symfony\Component\Security\Core\Encoder\UserPasswordEncoderInterface; | |||
use Symfony\Component\Translation\TranslatableMessage; | |||
use Symfony\Component\Routing\Annotation\Route; | |||
class UserController extends AbstractController | |||
class AccountAdminController extends AbstractController | |||
{ | |||
protected $em; | |||
protected EntityManagerInterface $entityManager; | |||
public function __construct(EntityManager $em) | |||
public function __construct(EntityManagerInterface $entityManager) | |||
{ | |||
$this->em = $em; | |||
$this->entityManager = $entityManager; | |||
} | |||
/** | |||
* @Route("/admin/account/profile", name="sov_admin_account_profile") | |||
*/ | |||
public function profile(Request $request): Response | |||
{ | |||
$user = $this->getUser(); | |||
@@ -30,23 +33,27 @@ class UserController extends AbstractController | |||
$form->handleRequest($request); | |||
if ($form->isSubmitted() && $form->isValid()) { | |||
$user = $form->getData(); | |||
$this->em->update($user); | |||
$this->em->flush(); | |||
$this->entityManager->update($user); | |||
$this->entityManager->flush(); | |||
$this->addFlash('success', new TranslatableMessage('form.account_profile.message.success', [], 'admin')); | |||
} | |||
return $this->render( | |||
'@LcSov/user/profile.html.twig', | |||
'@LcSov/admin/user/edit_profile.html.twig', | |||
[ | |||
'form' => $form->createView(), | |||
] | |||
); | |||
} | |||
/** | |||
* @Route("/admin/account/password", name="sov_admin_account_password") | |||
*/ | |||
public function changePassword(Request $request, UserPasswordEncoderInterface $passwordEncoder): Response | |||
{ | |||
$user = $this->getUser(); | |||
@@ -59,18 +66,16 @@ class UserController extends AbstractController | |||
$plainPassword = $form->get('plain_password')->getData(); | |||
// @TODO : créer UserManager | |||
$newPasswordEncoded = $passwordEncoder->encodePassword($user, $plainPassword); | |||
$user->setPassword($newPasswordEncoded); | |||
$user->setPassword($passwordEncoder->encodePassword($user, $plainPassword)); | |||
$this->em->update($user); | |||
$this->em->flush(); | |||
$this->entityManager->update($user); | |||
$this->entityManager->flush(); | |||
$this->addFlash('success', new TranslatableMessage('form.account_password.message.success', [], 'admin')); | |||
} | |||
return $this->render( | |||
'@LcSov/user/change_password.html.twig', | |||
'@LcSov/admin/user/edit_password.html.twig', | |||
[ | |||
'entity_class' => User::class, | |||
'form' => $form->createView() |
@@ -0,0 +1,25 @@ | |||
<?php | |||
namespace Lc\SovBundle\Controller\User; | |||
use EasyCorp\Bundle\EasyAdminBundle\Field\TextField; | |||
use Lc\SovBundle\Container\User\GroupUserContainer; | |||
use Lc\SovBundle\Controller\AbstractAdminController; | |||
use Lc\SovBundle\Factory\User\GroupUserFactory; | |||
abstract class GroupUserAdminController extends AbstractAdminController | |||
{ | |||
public function configureFields(string $pageName): iterable | |||
{ | |||
return [ | |||
TextField::new('title'), | |||
TextField::new('devAlias'), | |||
]; | |||
} | |||
public function createEntity(string $entityFqcn) | |||
{ | |||
return $this->get(GroupUserContainer::class)->getFactory()->create(); | |||
} | |||
} |
@@ -0,0 +1,50 @@ | |||
<?php | |||
namespace Lc\SovBundle\Controller\User; | |||
use EasyCorp\Bundle\EasyAdminBundle\Field\ChoiceField; | |||
use EasyCorp\Bundle\EasyAdminBundle\Field\EmailField; | |||
use EasyCorp\Bundle\EasyAdminBundle\Field\TextField; | |||
use Lc\SovBundle\Container\User\UserContainer; | |||
use Lc\SovBundle\Controller\AbstractAdminController; | |||
use Lc\SovBundle\Definition\RolesDefinition; | |||
use Lc\SovBundle\Definition\RolesDefinitionInterface; | |||
use Lc\SovBundle\Doctrine\EntityManager; | |||
use Lc\SovBundle\Factory\User\UserFactory; | |||
use Lc\SovBundle\Translation\TranslatorAdmin; | |||
use Symfony\Component\HttpFoundation\RequestStack; | |||
use Symfony\Component\HttpFoundation\Session\SessionInterface; | |||
abstract class UserAdminController extends AbstractAdminController | |||
{ | |||
protected RolesDefinitionInterface $rolesDefinition; | |||
public function __construct( | |||
SessionInterface $session, | |||
RequestStack $request, | |||
EntityManager $em, | |||
TranslatorAdmin $translatorAdmin, | |||
RolesDefinitionInterface $rolesDefinition | |||
) { | |||
$this->rolesDefinition = $rolesDefinition; | |||
} | |||
public function configureFields(string $pageName): iterable | |||
{ | |||
return [ | |||
EmailField::new('email'), | |||
TextField::new('lastname'), | |||
TextField::new('firstname'), | |||
ChoiceField::new('roles') | |||
->allowMultipleChoices() | |||
->autocomplete() | |||
->setChoices($this->rolesDefinition->getRolesList()) | |||
]; | |||
} | |||
public function createEntity(string $entityFqcn) | |||
{ | |||
return $this->get(UserContainer::class)->getFactory()->create(); | |||
} | |||
} |
@@ -0,0 +1,127 @@ | |||
<?php | |||
namespace Lc\SovBundle\Definition; | |||
abstract class AbstractSettingDefinition | |||
{ | |||
protected $settings = []; | |||
public function addSettingText(array $params): self | |||
{ | |||
$params['type'] = 'text'; | |||
$params['field'] = 'text'; | |||
return $this->addSetting($params); | |||
} | |||
public function addSettingTextarea(array $params): self | |||
{ | |||
$params['type'] = 'textarea'; | |||
$params['field'] = 'text'; | |||
return $this->addSetting($params); | |||
} | |||
public function addSettingTextareaAdvanced(array $params): self | |||
{ | |||
$params['type'] = 'textarea_advanced'; | |||
$params['field'] = 'text'; | |||
return $this->addSetting($params); | |||
} | |||
public function addSettingDate(array $params): self | |||
{ | |||
$params['type'] = 'date'; | |||
$params['field'] = 'date'; | |||
return $this->addSetting($params); | |||
} | |||
public function addSettingTime(array $params): self | |||
{ | |||
$params['type'] = 'time'; | |||
$params['field'] = 'date'; | |||
return $this->addSetting($params); | |||
} | |||
public function addSettingFile(array $params): self | |||
{ | |||
$params['type'] = 'file'; | |||
$params['field'] = 'file'; | |||
return $this->addSetting($params); | |||
} | |||
public function addSettingImage(array $params): self | |||
{ | |||
$params['type'] = 'image'; | |||
$params['field'] = 'file'; | |||
return $this->addSetting($params); | |||
} | |||
public function addSettingSelect(array $params): self | |||
{ | |||
$params['type'] = 'select'; | |||
$params['field'] = 'text'; | |||
return $this->addSetting($params); | |||
} | |||
public function addSettingRadio(array $params): self | |||
{ | |||
$params['type'] = 'radio'; | |||
$params['field'] = 'text'; | |||
return $this->addSetting($params); | |||
} | |||
public function addSetting($params) | |||
{ | |||
$name = $params['name']; | |||
$category = $params['category']; | |||
if (!isset($this->settings[$category])) { | |||
$this->settings[$category] = []; | |||
} | |||
$this->settings[$category][$name] = $params; | |||
return $this; | |||
} | |||
public function getSettings(): array | |||
{ | |||
return $this->settings; | |||
} | |||
public function getSettingsByCategory($category) | |||
{ | |||
$settings = $this->getSettings(); | |||
if (isset($settings[$category])) { | |||
return $settings[$category]; | |||
} | |||
return []; | |||
} | |||
public function getSettingByName($name): ?array | |||
{ | |||
$settings = $this->getSettings(); | |||
foreach ($settings as $category => $settingsCategory) { | |||
foreach ($settingsCategory as $nameSetting => $setting) { | |||
if ($nameSetting == $name) { | |||
return $setting; | |||
} | |||
} | |||
} | |||
return null; | |||
} | |||
public function getSettingType($name): ?string | |||
{ | |||
$setting = $this->getSettingByName($name); | |||
if ($setting) { | |||
return $setting['type']; | |||
} | |||
return null; | |||
} | |||
} |
@@ -0,0 +1,51 @@ | |||
<?php | |||
namespace Lc\SovBundle\Definition; | |||
class RolesDefinition implements RolesDefinitionInterface | |||
{ | |||
const ROLE_USER = 'ROLE_USER' ; | |||
const ROLE_ADMIN = 'ROLE_ADMIN' ; | |||
const ROLE_SUPER_ADMIN = 'ROLE_SUPER_ADMIN' ; | |||
protected $roles = array( | |||
self::ROLE_USER => [ | |||
'label' => 'Utilisateurs', | |||
'role' => self::ROLE_USER, | |||
], | |||
self::ROLE_ADMIN => [ | |||
'label' => 'Administrateurs', | |||
'role' => self::ROLE_ADMIN, | |||
], | |||
self::ROLE_SUPER_ADMIN => [ | |||
'label' => 'SuperAdmin', | |||
'role' => self::ROLE_SUPER_ADMIN, | |||
], | |||
); | |||
public function getRoles(): array | |||
{ | |||
return $this->roles; | |||
} | |||
public function getRole($role): ?array | |||
{ | |||
if (isset($this->roles[$role])) { | |||
return $this->roles[$role]; | |||
} else { | |||
return null; | |||
} | |||
} | |||
public function getRolesList(): array | |||
{ | |||
$rolesList = array(); | |||
foreach ($this->roles as $role) { | |||
$rolesList[$role['label']] = $role['role']; | |||
} | |||
return $rolesList; | |||
} | |||
} |
@@ -0,0 +1,16 @@ | |||
<?php | |||
namespace Lc\SovBundle\Definition; | |||
interface RolesDefinitionInterface | |||
{ | |||
public function getRoles(): array; | |||
public function getRole($role): ?array; | |||
public function getRolesList(): array; | |||
} |
@@ -0,0 +1,41 @@ | |||
<?php | |||
namespace Lc\SovBundle\Definition; | |||
class SiteSettingDefinition extends AbstractSettingDefinition implements SiteSettingDefinitionInterface | |||
{ | |||
const CATEGORY_GENERAL = 'general'; | |||
const SETTING_MAINTENANCE = 'maintenance'; | |||
const SETTING_MAINTENANCE_IP_AUTHORIZED = 'maintenanceIpAuthorized'; | |||
public function __construct() | |||
{ | |||
$this->addSettingSelect( | |||
[ | |||
'category' => self::CATEGORY_GENERAL, | |||
'name' => self::SETTING_MAINTENANCE, | |||
'choices' => [ | |||
'Non' => 0, | |||
'Oui' => 1, | |||
] | |||
] | |||
); | |||
$this->addSettingText( | |||
[ | |||
'category' => self::CATEGORY_GENERAL, | |||
'name' => self::SETTING_MAINTENANCE_IP_AUTHORIZED, | |||
] | |||
); | |||
} | |||
public function getCategories() | |||
{ | |||
return [ | |||
self::CATEGORY_GENERAL | |||
]; | |||
} | |||
} |
@@ -0,0 +1,8 @@ | |||
<?php | |||
namespace Lc\SovBundle\Definition; | |||
interface SiteSettingDefinitionInterface | |||
{ | |||
} |
@@ -12,21 +12,35 @@ use Symfony\Component\Config\Definition\ConfigurationInterface; | |||
*/ | |||
class Configuration implements ConfigurationInterface | |||
{ | |||
/** | |||
* {@inheritdoc} | |||
*/ | |||
public function getConfigTreeBuilder() | |||
{ | |||
$treeBuilder = new TreeBuilder('lc_sov'); | |||
$rootNode = $treeBuilder->getRootNode(); | |||
/** | |||
* {@inheritdoc} | |||
*/ | |||
public function getConfigTreeBuilder() | |||
{ | |||
$treeBuilder = new TreeBuilder('lc_sov'); | |||
$rootNode = $treeBuilder->getRootNode(); | |||
$rootNode | |||
->children() | |||
//->scalarNode('dashboard_default')->defaultValue('App\Controller\Admin\DashboardController')->end() | |||
->scalarNode('homepage_route')->end() | |||
->end(); | |||
$rootNode | |||
->children() | |||
//->scalarNode('dashboard_default')->defaultValue('App\Controller\Admin\DashboardController')->end() | |||
->scalarNode('homepage_route')->end() | |||
->arrayNode('login_redirection') | |||
->children() | |||
->scalarNode('redirect_referer') | |||
->defaultValue(true) | |||
->end() | |||
->arrayNode('roles_redirection') | |||
->arrayPrototype() | |||
->children() | |||
->scalarNode('role')->end() | |||
->scalarNode('redirect')->end() | |||
->end() | |||
->end() | |||
->end() | |||
->end() | |||
->end(); | |||
return $treeBuilder; | |||
} | |||
return $treeBuilder; | |||
} | |||
} |
@@ -6,7 +6,6 @@ use Doctrine\ORM\Decorator\EntityManagerDecorator; | |||
use Doctrine\ORM\EntityManager as DoctrineEntityManager; | |||
use Doctrine\ORM\EntityManagerInterface; | |||
use Lc\SovBundle\Event\EntityManager\EntityManagerEvent; | |||
use Lc\SovBundle\Doctrine\EntityInterface; | |||
use Symfony\Component\EventDispatcher\EventDispatcherInterface; | |||
/** | |||
@@ -27,6 +26,11 @@ class EntityManager extends EntityManagerDecorator | |||
parent::__construct($wrapped); | |||
} | |||
public function createQueryBuilder() | |||
{ | |||
return new QueryBuilder($this); | |||
} | |||
public function getRepository($className) | |||
{ | |||
return $this->wrapped->getRepository($this->getEntityName($className)); | |||
@@ -39,31 +43,43 @@ class EntityManager extends EntityManagerDecorator | |||
return new $entityName; | |||
} | |||
public function create(EntityInterface $entity): self | |||
public function create(EntityInterface $entity, bool $dispatchEvent = true): self | |||
{ | |||
if($dispatchEvent) { | |||
$this->eventDispatcher->dispatch(new EntityManagerEvent($entity), EntityManagerEvent::PRE_CREATE_EVENT); | |||
} | |||
$this->persist($entity); | |||
$this->eventDispatcher->dispatch(new EntityManagerEvent($entity), EntityManagerEvent::CREATE_EVENT); | |||
if($dispatchEvent) { | |||
$this->eventDispatcher->dispatch(new EntityManagerEvent($entity), EntityManagerEvent::POST_CREATE_EVENT); | |||
} | |||
return $this; | |||
} | |||
public function update(EntityInterface $entity): self | |||
public function update(EntityInterface $entity, bool $dispatchEvent = true): self | |||
{ | |||
if($dispatchEvent){ | |||
$this->eventDispatcher->dispatch(new EntityManagerEvent($entity), EntityManagerEvent::PRE_UPDATE_EVENT); | |||
} | |||
$this->persist($entity); | |||
$this->eventDispatcher->dispatch(new EntityManagerEvent($entity), EntityManagerEvent::UPDATE_EVENT); | |||
if($dispatchEvent) { | |||
$this->eventDispatcher->dispatch(new EntityManagerEvent($entity), EntityManagerEvent::POST_UPDATE_EVENT); | |||
} | |||
return $this; | |||
} | |||
public function delete(EntityInterface $entity): self | |||
public function delete(EntityInterface $entity, bool $dispatchEvent = true): self | |||
{ | |||
if($dispatchEvent) { | |||
$this->eventDispatcher->dispatch(new EntityManagerEvent($entity), EntityManagerEvent::PRE_DELETE_EVENT); | |||
} | |||
$this->remove($entity); | |||
$this->eventDispatcher->dispatch(new EntityManagerEvent($entity), EntityManagerEvent::DELETE_EVENT); | |||
if($dispatchEvent) { | |||
$this->eventDispatcher->dispatch(new EntityManagerEvent($entity), EntityManagerEvent::POST_DELETE_EVENT); | |||
} | |||
return $this; | |||
} | |||
public function flush($entity=null): self | |||
public function flush($entity = null): self | |||
{ | |||
$this->wrapped->flush($entity); | |||
@@ -0,0 +1,27 @@ | |||
<?php | |||
namespace Lc\SovBundle\Doctrine\Extension; | |||
use Doctrine\ORM\Mapping as ORM; | |||
use Gedmo\Mapping\Annotation as Gedmo; | |||
use Lc\SovBundle\Model\User\UserInterface; | |||
trait BlameableNullableTrait | |||
{ | |||
/** | |||
* @Gedmo\Blameable(on="create") | |||
* @ORM\ManyToOne(targetEntity="Lc\SovBundle\Model\User\UserInterface") | |||
* @ORM\JoinColumn(nullable=true) | |||
*/ | |||
protected $createdBy; | |||
/** | |||
* @Gedmo\Blameable(on="update") | |||
* @ORM\ManyToOne(targetEntity="Lc\SovBundle\Model\User\UserInterface") | |||
* @ORM\JoinColumn(nullable=true) | |||
*/ | |||
protected $updatedBy; | |||
} |
@@ -0,0 +1,15 @@ | |||
<?php | |||
namespace Lc\SovBundle\Doctrine\Extension; | |||
trait ClearIdTrait | |||
{ | |||
public function clearId($id): self | |||
{ | |||
$this->id = $id; | |||
return $this; | |||
} | |||
} |
@@ -9,7 +9,7 @@ trait SluggableTrait | |||
{ | |||
/** | |||
* @ORM\Column(type="string", length=255) | |||
* @Gedmo\Slug(fields={"title"}) | |||
* @Gedmo\Slug(fields={"title"}, unique=true) | |||
*/ | |||
protected $slug; | |||
@@ -0,0 +1,34 @@ | |||
<?php | |||
namespace Lc\SovBundle\Doctrine; | |||
use Doctrine\ORM\QueryBuilder as DoctrineQueryBuilder; | |||
/** | |||
* class QueryBuilder. | |||
* | |||
* @author La clic !!!! | |||
*/ | |||
class QueryBuilder extends DoctrineQueryBuilder | |||
{ | |||
public function andWhereParent($dqlId, $entityId):self | |||
{ | |||
$this->andWhere($dqlId.'.parent = :entityId'); | |||
$this->setParameter('entityId', $entityId); | |||
return $this; | |||
} | |||
public function andWhereParentIsNull($dqlId):self | |||
{ | |||
$this->andWhere($dqlId.'.parent IS NULL'); | |||
return $this; | |||
} | |||
public function andWhereStatus($dqlId, $status){ | |||
$this->andWhere($dqlId.'.status = :status'); | |||
$this->setParameter('status', $status); | |||
return $this; | |||
} | |||
} |
@@ -0,0 +1,28 @@ | |||
<?php | |||
namespace Lc\SovBundle\Event; | |||
use Lc\SovBundle\Doctrine\EntityInterface; | |||
use Symfony\Contracts\EventDispatcher\Event; | |||
/** | |||
* class EntityEvent. | |||
* | |||
* @author Simon Vieille <simon@deblan.fr> | |||
*/ | |||
class EntityComponentEvent extends Event | |||
{ | |||
const DUPLICATE_EVENT = 'entity_component_event.duplicate'; | |||
protected EntityInterface $entity; | |||
public function __construct(EntityInterface $entity) | |||
{ | |||
$this->entity = $entity; | |||
} | |||
public function getEntity(): EntityInterface | |||
{ | |||
return $this->entity; | |||
} | |||
} |
@@ -12,9 +12,12 @@ use Symfony\Contracts\EventDispatcher\Event; | |||
*/ | |||
class EntityManagerEvent extends Event | |||
{ | |||
const CREATE_EVENT = 'entity_manager_event.create'; | |||
const UPDATE_EVENT = 'entity_manager_event.update'; | |||
const DELETE_EVENT = 'entity_manager_event.delete'; | |||
const PRE_CREATE_EVENT = 'entity_manager_event.pre_create'; | |||
const POST_CREATE_EVENT = 'entity_manager_event.post_create'; | |||
const PRE_UPDATE_EVENT = 'entity_manager_event.pre_update'; | |||
const POST_UPDATE_EVENT = 'entity_manager_event.post_update'; | |||
const PRE_DELETE_EVENT = 'entity_manager_event.pre_delete'; | |||
const POST_DELETE_EVENT = 'entity_manager_event.post_delete'; | |||
protected EntityInterface $entity; | |||
@@ -1,73 +0,0 @@ | |||
<?php | |||
namespace Lc\SovBundle\EventSubscriber\Action; | |||
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 EasyCorp\Bundle\EasyAdminBundle\Router\AdminUrlGenerator; | |||
use Gedmo\Translatable\TranslatableListener; | |||
use Lc\SovBundle\Doctrine\Extension\TranslatableInterface; | |||
use Lc\SovBundle\Doctrine\EntityManager; | |||
use Symfony\Component\EventDispatcher\EventSubscriberInterface; | |||
use function Symfony\Component\Translation\t; | |||
class ActionEasyAdminSubscriber implements EventSubscriberInterface | |||
{ | |||
protected $em; | |||
protected $adminUrlGenerator; | |||
public function __construct(EntityManager $entityManager, AdminUrlGenerator $adminUrlGenerator) | |||
{ | |||
$this->em = $entityManager; | |||
$this->adminUrlGenerator = $adminUrlGenerator; | |||
} | |||
public static function getSubscribedEvents() | |||
{ | |||
return [ | |||
AfterCrudActionEvent::class => ['overrideSortAction'], | |||
]; | |||
} | |||
public function overrideSortAction(AfterCrudActionEvent $event) | |||
{ | |||
$actions = $event->getResponseParameters()->get('global_actions'); | |||
if ($actions) { | |||
foreach ($actions as $i=>$action) { | |||
//récriture du bouton 'retour au parent' | |||
if ($action->getName() == 'index_parent') { | |||
$entity = $event->getAdminContext()->getEntity()->getInstance(); | |||
if ($entity !== null) { | |||
if($entity->getParent() !==null){ | |||
$url = $this->adminUrlGenerator | |||
->setController($event->getAdminContext()->getCrud()->getControllerFqcn()) | |||
->set('entityId', $entity->getParent()->getId()) | |||
->generateUrl(); | |||
$action->setLinkUrl($url); | |||
} | |||
}else{ | |||
unset($actions[$i]); | |||
} | |||
} | |||
if ($action->getName() == 'sort') { | |||
$entityId = $event->getAdminContext()->getRequest()->get('entityId'); | |||
if ($entityId != null) { | |||
$url = $this->adminUrlGenerator | |||
->setController($event->getAdminContext()->getCrud()->getControllerFqcn()) | |||
->setAction($action->getName()) | |||
->set('entityId', $entityId) | |||
->generateUrl(); | |||
$action->setLinkUrl($url); | |||
} | |||
} | |||
} | |||
} | |||
} | |||
} |
@@ -9,7 +9,7 @@ use Symfony\Component\EventDispatcher\EventSubscriberInterface; | |||
use Symfony\Component\HttpFoundation\Session\SessionInterface; | |||
use Symfony\Component\Translation\TranslatableMessage; | |||
class EasyAdminEventSubscriber implements EventSubscriberInterface | |||
class FlashMessageAdminEventSubscriber implements EventSubscriberInterface | |||
{ | |||
protected $session ; | |||
@@ -0,0 +1,109 @@ | |||
<?php | |||
namespace Lc\SovBundle\EventSubscriber; | |||
use Doctrine\ORM\EntityManagerInterface; | |||
use Lc\SovBundle\Definition\SiteSettingDefinitionInterface; | |||
use Lc\SovBundle\Factory\Setting\SiteSettingFactory; | |||
use Lc\SovBundle\Factory\Site\SiteFactory; | |||
use Lc\SovBundle\Repository\Setting\SiteSettingRepository; | |||
use Lc\SovBundle\Repository\Site\SiteRepository; | |||
use Lc\SovBundle\Repository\Site\SiteStore; | |||
use Lc\SovBundle\Solver\Setting\SettingSolver; | |||
use Symfony\Component\EventDispatcher\EventSubscriberInterface; | |||
use Symfony\Component\HttpKernel\KernelEvents; | |||
class SiteSettingEventSubscriber implements EventSubscriberInterface | |||
{ | |||
protected EntityManagerInterface $entityManager; | |||
protected SiteSettingDefinitionInterface $siteSettingDefinition; | |||
protected SiteSettingFactory $siteSettingFactory; | |||
protected SiteSettingRepository $siteSettingRepository; | |||
protected SiteStore $siteStore; | |||
protected SiteFactory $siteFactory; | |||
protected SettingSolver $settingSolver; | |||
public function __construct( | |||
EntityManagerInterface $entityManager, | |||
SiteSettingRepository $siteSettingRepository, | |||
SiteStore $siteStore, | |||
SiteSettingDefinitionInterface $siteSettingDefinition, | |||
SiteSettingFactory $siteSettingFactory, | |||
SiteFactory $siteFactory, | |||
SettingSolver $settingSolver | |||
) { | |||
$this->entityManager = $entityManager; | |||
$this->siteSettingDefinition = $siteSettingDefinition; | |||
$this->siteSettingFactory = $siteSettingFactory; | |||
$this->siteSettingRepository = $siteSettingRepository; | |||
$this->siteStore = $siteStore; | |||
$this->siteFactory = $siteFactory; | |||
$this->settingSolver = $settingSolver; | |||
} | |||
public static function getSubscribedEvents() | |||
{ | |||
return [ | |||
KernelEvents::CONTROLLER => ['initSettings'] | |||
]; | |||
} | |||
public function initSettings() | |||
{ | |||
$site = $this->getSiteDefault(); | |||
if (!$site) { | |||
$site = $this->siteFactory->create('default'); | |||
$this->entityManager->persist($site); | |||
$this->entityManager->flush($site); | |||
} | |||
$settings = $this->siteSettingDefinition->getSettings(); | |||
$factory = $this->siteSettingFactory; | |||
foreach ($settings as $category => $settingList) { | |||
foreach ($settingList as $settingName => $setting) { | |||
$entitySetting = $this->settingSolver->getSetting($site, $settingName); | |||
if (!$entitySetting) { | |||
$text = null; | |||
$date = null; | |||
$file = null; | |||
$fieldValue = isset($setting['default']) ? $setting['default'] : null; | |||
if($setting['field'] == 'text') { | |||
$text = $fieldValue; | |||
} | |||
if($setting['field'] == 'date') { | |||
$date = $fieldValue; | |||
} | |||
if($setting['field'] == 'file') { | |||
$file = $fieldValue; | |||
} | |||
$entitySetting = $factory->create($site, $setting['name'], $text, $date, $file); | |||
$this->entityManager->persist($entitySetting); | |||
} else { | |||
$methodGetValue = 'get' . ucfirst($setting['field']); | |||
if ($entitySetting->$methodGetValue() === null | |||
&& isset($setting['default']) | |||
&& $setting['default'] !== null) { | |||
$methodSetValue = 'set' . ucfirst($setting['field']); | |||
$entitySetting->$methodSetValue($setting['default']); | |||
$this->entityManager->update($entitySetting); | |||
} | |||
} | |||
} | |||
} | |||
$this->entityManager->flush(); | |||
} | |||
public function getSiteDefault() | |||
{ | |||
return $this->siteStore->getOneByDevAlias('default'); | |||
} | |||
} |
@@ -0,0 +1,52 @@ | |||
<?php | |||
namespace Lc\SovBundle\EventSubscriber; | |||
use Doctrine\ORM\EntityManagerInterface; | |||
use Lc\SovBundle\Doctrine\EntityInterface; | |||
use Lc\SovBundle\Doctrine\Extension\SluggableInterface; | |||
use Lc\SovBundle\Doctrine\Extension\SortableInterface; | |||
use Lc\SovBundle\Doctrine\Extension\StatusInterface; | |||
use Lc\SovBundle\Doctrine\Extension\TreeInterface; | |||
use Lc\SovBundle\Event\EntityComponentEvent; | |||
use Lc\SovBundle\Event\EntityManager\EntityManagerEvent; | |||
use Lc\SovBundle\Repository\AbstractRepositoryInterface; | |||
use Symfony\Component\EventDispatcher\EventSubscriberInterface; | |||
class SluggablePropertyEventSubscriber implements EventSubscriberInterface | |||
{ | |||
protected $em; | |||
protected $adminUrlGenerator; | |||
public function __construct(EntityManagerInterface $entityManager) | |||
{ | |||
$this->em = $entityManager; | |||
} | |||
public static function getSubscribedEvents() | |||
{ | |||
return [ | |||
EntityComponentEvent::DUPLICATE_EVENT => ['setSluggablePropertyDuplicateEvent'], | |||
EntityManagerEvent::POST_UPDATE_EVENT => ['setSluggablePropertyUpdateEvent'], | |||
]; | |||
} | |||
public function setSluggablePropertyDuplicateEvent(EntityComponentEvent $event) | |||
{ | |||
$entity = $event->getEntity(); | |||
if ($entity instanceof SluggableInterface) { | |||
$entity->clearId(null); | |||
$entity->setSlug(null); | |||
} | |||
} | |||
public function setSluggablePropertyUpdateEvent(EntityManagerEvent $event) | |||
{ | |||
$entity = $event->getEntity(); | |||
if ($entity instanceof SluggableInterface) { | |||
$entity->setSlug(null); | |||
} | |||
} | |||
} |
@@ -12,7 +12,7 @@ use Lc\SovBundle\Event\EntityManager\EntityManagerEvent; | |||
use Lc\SovBundle\Repository\AbstractRepositoryInterface; | |||
use Symfony\Component\EventDispatcher\EventSubscriberInterface; | |||
class CreateEntityEventSubscriber implements EventSubscriberInterface | |||
class SortablePropertyEventSubscriber implements EventSubscriberInterface | |||
{ | |||
protected $em; | |||
protected $adminUrlGenerator; | |||
@@ -25,11 +25,11 @@ class CreateEntityEventSubscriber implements EventSubscriberInterface | |||
public static function getSubscribedEvents() | |||
{ | |||
return [ | |||
EntityManagerEvent::CREATE_EVENT => ['createEntity'], | |||
EntityManagerEvent::PRE_CREATE_EVENT => ['setCommonProperty'], | |||
]; | |||
} | |||
public function createEntity(EntityManagerEvent $event) | |||
public function setCommonProperty(EntityManagerEvent $event) | |||
{ | |||
$entity = $event->getEntity(); | |||
$entityRepository = $this->em->getRepository(get_class($entity)); |
@@ -0,0 +1,47 @@ | |||
<?php | |||
namespace Lc\SovBundle\EventSubscriber\User; | |||
use Doctrine\ORM\EntityManagerInterface; | |||
use Lc\SovBundle\Doctrine\EntityInterface; | |||
use Lc\SovBundle\Doctrine\Extension\SortableInterface; | |||
use Lc\SovBundle\Doctrine\Extension\StatusInterface; | |||
use Lc\SovBundle\Doctrine\Extension\TreeInterface; | |||
use Lc\SovBundle\Event\EntityManager\EntityManagerEvent; | |||
use Lc\SovBundle\Model\User\UserInterface; | |||
use Lc\SovBundle\Repository\AbstractRepositoryInterface; | |||
use Symfony\Component\EventDispatcher\EventSubscriberInterface; | |||
use Symfony\Component\Security\Core\Encoder\PasswordEncoderInterface; | |||
use Symfony\Component\Security\Core\Encoder\UserPasswordEncoderInterface; | |||
class UserPasswordEventSubscriber implements EventSubscriberInterface | |||
{ | |||
protected $passwordEncoder; | |||
public function __construct(UserPasswordEncoderInterface $passwordEncoder) | |||
{ | |||
$this->passwordEncoder = $passwordEncoder; | |||
} | |||
public static function getSubscribedEvents() | |||
{ | |||
return [ | |||
EntityManagerEvent::PRE_CREATE_EVENT => ['setUserPasswordIfNull'], | |||
]; | |||
} | |||
public function setUserPasswordIfNull(EntityManagerEvent $event) | |||
{ | |||
$entity = $event->getEntity(); | |||
if ($entity instanceof UserInterface) { | |||
if ($entity->getPassword() == null) { | |||
$password = $this->passwordEncoder->encodePassword($entity, $entity->generatePassword()); | |||
$entity->setPassword($password); | |||
} | |||
} | |||
} | |||
} |
@@ -0,0 +1,8 @@ | |||
<?php | |||
namespace Lc\SovBundle\Factory; | |||
abstract class AbstractFactory implements FactoryInterface | |||
{ | |||
} |
@@ -0,0 +1,8 @@ | |||
<?php | |||
namespace Lc\SovBundle\Factory; | |||
interface FactoryInterface | |||
{ | |||
} |
@@ -0,0 +1,18 @@ | |||
<?php | |||
namespace Lc\SovBundle\Factory\File; | |||
use App\Entity\File\File; | |||
use Lc\SovBundle\Factory\AbstractFactory; | |||
use Lc\SovBundle\Model\File\FileInterface; | |||
class FileFactory extends AbstractFactory | |||
{ | |||
public function create(): FileInterface | |||
{ | |||
$file = new File(); | |||
return $file; | |||
} | |||
} |
@@ -0,0 +1,18 @@ | |||
<?php | |||
namespace Lc\SovBundle\Factory\Newsletter; | |||
use App\Entity\Newsletter\Newsletter; | |||
use Lc\SovBundle\Factory\AbstractFactory; | |||
use Lc\SovBundle\Model\Newsletter\NewsletterInterface; | |||
class NewsletterFactory extends AbstractFactory | |||
{ | |||
public function create(): NewsletterInterface | |||
{ | |||
$newsletter = new Newsletter(); | |||
return $newsletter; | |||
} | |||
} |
@@ -0,0 +1,25 @@ | |||
<?php | |||
namespace Lc\SovBundle\Factory\Reminder; | |||
use App\Entity\Reminder\Reminder; | |||
use Lc\SovBundle\Factory\AbstractFactory; | |||
use Lc\SovBundle\Model\Reminder\ReminderInterface; | |||
class ReminderFactory extends AbstractFactory implements ReminderFactoryInterface | |||
{ | |||
public function create( | |||
string $crudAction = null, | |||
string $crudControllerFqcn = null, | |||
int $entityId = null | |||
): ReminderInterface { | |||
$reminder = new Reminder(); | |||
$reminder->setCrudAction($crudAction); | |||
$reminder->setCrudControllerFqcn($crudControllerFqcn); | |||
$reminder->setEntityId($entityId); | |||
return $reminder; | |||
} | |||
} |
@@ -0,0 +1,8 @@ | |||
<?php | |||
namespace Lc\SovBundle\Factory\Reminder; | |||
interface ReminderFactoryInterface | |||
{ | |||
} |
@@ -0,0 +1,25 @@ | |||
<?php | |||
namespace Lc\SovBundle\Factory\Setting; | |||
use App\Entity\Setting\SiteSetting; | |||
use Lc\SovBundle\Factory\AbstractFactory; | |||
use Lc\SovBundle\Model\File\FileInterface; | |||
use Lc\SovBundle\Model\Setting\SiteSettingInterface; | |||
use Lc\SovBundle\Model\Site\SiteInterface; | |||
class SiteSettingFactory extends AbstractFactory implements SiteSettingFactoryInterface | |||
{ | |||
public function create(SiteInterface $site, string $name, string $text = null, \DateTime $date = null, FileInterface $file = null): SiteSettingInterface | |||
{ | |||
$siteSetting = new SiteSetting(); | |||
$siteSetting->setSite($site); | |||
$siteSetting->setName($name); | |||
$siteSetting->setText($text); | |||
$siteSetting->setDate($date); | |||
$siteSetting->setFile($file); | |||
return $siteSetting; | |||
} | |||
} |
@@ -0,0 +1,8 @@ | |||
<?php | |||
namespace Lc\SovBundle\Factory\Setting; | |||
interface SiteSettingFactoryInterface | |||
{ | |||
} |
@@ -0,0 +1,18 @@ | |||
<?php | |||
namespace Lc\SovBundle\Factory\Site; | |||
use App\Entity\Site\News; | |||
use Lc\SovBundle\Factory\AbstractFactory; | |||
use Lc\SovBundle\Model\Site\NewsInterface; | |||
class NewsFactory extends AbstractFactory implements NewsFactoryInterface | |||
{ | |||
public function create(): NewsInterface | |||
{ | |||
$news = new News(); | |||
return $news; | |||
} | |||
} |
@@ -0,0 +1,8 @@ | |||
<?php | |||
namespace Lc\SovBundle\Factory\Site; | |||
interface NewsFactoryInterface | |||
{ | |||
} |
@@ -0,0 +1,17 @@ | |||
<?php | |||
namespace Lc\SovBundle\Factory\Site; | |||
use App\Entity\Site\Page; | |||
use Lc\SovBundle\Factory\AbstractFactory; | |||
use Lc\SovBundle\Model\Site\PageInterface; | |||
class PageFactory extends AbstractFactory implements PageFactoryInterface | |||
{ | |||
public function create(): PageInterface | |||
{ | |||
$page = new Page(); | |||
return $page; | |||
} | |||
} |
@@ -0,0 +1,8 @@ | |||
<?php | |||
namespace Lc\SovBundle\Factory\Site; | |||
interface PageFactoryInterface | |||
{ | |||
} |
@@ -0,0 +1,19 @@ | |||
<?php | |||
namespace Lc\SovBundle\Factory\Site; | |||
use App\Entity\Site\Site; | |||
use Lc\SovBundle\Factory\AbstractFactory; | |||
use Lc\SovBundle\Model\Site\SiteInterface; | |||
class SiteFactory extends AbstractFactory implements SiteFactoryInterface | |||
{ | |||
public function create(string $devAlias = null): SiteInterface | |||
{ | |||
$site = new Site(); | |||
$site->setDevAlias($devAlias); | |||
return $site; | |||
} | |||
} |
@@ -0,0 +1,8 @@ | |||
<?php | |||
namespace Lc\SovBundle\Factory\Site; | |||
interface SiteFactoryInterface | |||
{ | |||
} |
@@ -0,0 +1,24 @@ | |||
<?php | |||
namespace Lc\SovBundle\Factory\Ticket; | |||
use App\Entity\Ticket\Ticket; | |||
use Lc\SovBundle\Factory\AbstractFactory; | |||
use Lc\SovBundle\Model\Ticket\TicketInterface; | |||
use Lc\SovBundle\Model\Ticket\TicketModel; | |||
class TicketFactory extends AbstractFactory implements TicketFactoryInterface | |||
{ | |||
public function create(): TicketInterface | |||
{ | |||
$ticket = new Ticket(); | |||
$ticketMessageFactory = new TicketMessageFactory(); | |||
$ticketMessage = $ticketMessageFactory->create($ticket) ; | |||
$ticket->setStatus(TicketModel::TICKET_STATUS_OPEN); | |||
$ticket->addTicketMessage($ticketMessage) ; | |||
return $ticket; | |||
} | |||
} |
@@ -0,0 +1,8 @@ | |||
<?php | |||
namespace Lc\SovBundle\Factory\Ticket; | |||
interface TicketFactoryInterface | |||
{ | |||
} |
@@ -0,0 +1,21 @@ | |||
<?php | |||
namespace Lc\SovBundle\Factory\Ticket; | |||
use App\Entity\Ticket\TicketMessage; | |||
use Lc\SovBundle\Factory\AbstractFactory; | |||
use Lc\SovBundle\Model\Ticket\TicketInterface; | |||
use Lc\SovBundle\Model\Ticket\TicketMessageInterface; | |||
class TicketMessageFactory extends AbstractFactory implements TicketMessageFactoryInterface | |||
{ | |||
public function create(TicketInterface $ticket): TicketMessageInterface | |||
{ | |||
$ticketMessage = new TicketMessage(); | |||
$ticketMessage->setTicket($ticket); | |||
$ticketMessage->setStatus(1); | |||
return $ticketMessage; | |||
} | |||
} |
@@ -0,0 +1,8 @@ | |||
<?php | |||
namespace Lc\SovBundle\Factory\Ticket; | |||
interface TicketMessageFactoryInterface | |||
{ | |||
} |
@@ -0,0 +1,17 @@ | |||
<?php | |||
namespace Lc\SovBundle\Factory\User; | |||
use App\Entity\User\GroupUser; | |||
use Lc\SovBundle\Factory\AbstractFactory; | |||
use Lc\SovBundle\Model\User\GroupUserInterface; | |||
class GroupUserFactory extends AbstractFactory implements GroupUserFactoryInterface | |||
{ | |||
public function create(): GroupUserInterface | |||
{ | |||
$groupUser = new GroupUser(); | |||
return $groupUser; | |||
} | |||
} |
@@ -0,0 +1,8 @@ | |||
<?php | |||
namespace Lc\SovBundle\Factory\User; | |||
interface GroupUserFactoryInterface | |||
{ | |||
} |
@@ -0,0 +1,17 @@ | |||
<?php | |||
namespace Lc\SovBundle\Factory\User; | |||
use App\Entity\User\User; | |||
use Lc\SovBundle\Factory\AbstractFactory; | |||
use Lc\SovBundle\Model\User\UserInterface; | |||
class UserFactory extends AbstractFactory | |||
{ | |||
public function create(): UserInterface | |||
{ | |||
$user = new User(); | |||
return $user; | |||
} | |||
} |
@@ -0,0 +1,8 @@ | |||
<?php | |||
namespace Lc\SovBundle\Factory\User; | |||
interface UserFactoryInterface | |||
{ | |||
} |
@@ -4,9 +4,7 @@ namespace Lc\SovBundle\Field; | |||
use EasyCorp\Bundle\EasyAdminBundle\Contracts\Field\FieldInterface; | |||
use EasyCorp\Bundle\EasyAdminBundle\Field\FieldTrait; | |||
use Lc\SovBundle\Form\Type\FileManagerType; | |||
use Symfony\Component\Form\Extension\Core\Type\CheckboxType; | |||
use Symfony\Component\Form\Extension\Core\Type\ChoiceType; | |||
use Symfony\Component\Form\Extension\Core\Type\TextType; | |||
/** | |||
@@ -21,7 +19,7 @@ final class BooleanField implements FieldInterface | |||
return (new self()) | |||
->setProperty($propertyName) | |||
->setLabel($label) | |||
->setTemplatePath('@LcSov/adminlte/crud/field/toggle.html.twig') | |||
->setTemplatePath('@LcSov/adminlte/crud/field/boolean.html.twig') | |||
->setFormType(CheckboxType::class); | |||
} | |||
@@ -11,69 +11,68 @@ 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('@LcSov/adminlte/crud/field/collection.html.twig') | |||
->setFormType(CollectionType::class) | |||
/*->addWebpackEncoreEntries('adminlte-field-collection')*/ | |||
->setFormTypeOption('allow_add', true) | |||
->setFormTypeOption('allow_delete', true) | |||
->setFormTypeOption('entry_options', array('label' => false)) | |||
->addCssClass('field-collection') | |||
->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; | |||
} | |||
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('@LcSov/adminlte/crud/field/collection.html.twig') | |||
->setFormType(CollectionType::class) | |||
/*->addWebpackEncoreEntries('adminlte-field-collection')*/ | |||
->setFormTypeOption('allow_add', true) | |||
->setFormTypeOption('allow_delete', true) | |||
->setFormTypeOption('entry_options', array('label' => false)) | |||
->addCssClass('field-collection') | |||
->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; | |||
} | |||
} |
@@ -4,7 +4,7 @@ namespace Lc\SovBundle\Field; | |||
use EasyCorp\Bundle\EasyAdminBundle\Contracts\Field\FieldInterface; | |||
use EasyCorp\Bundle\EasyAdminBundle\Field\FieldTrait; | |||
use Lc\SovBundle\Form\Type\Crud\FileManagerType; | |||
use Lc\SovBundle\Form\Common\FileManagerType; | |||
use Symfony\Component\Form\Extension\Core\Type\TextType; | |||
/** |
@@ -0,0 +1,67 @@ | |||
<?php | |||
namespace Lc\SovBundle\Field\Filter; | |||
use Doctrine\ORM\EntityRepository; | |||
use Doctrine\ORM\QueryBuilder; | |||
use EasyCorp\Bundle\EasyAdminBundle\Dto\FieldDto; | |||
use Symfony\Bridge\Doctrine\Form\Type\EntityType; | |||
use Symfony\Component\Form\FormBuilderInterface; | |||
/** | |||
* @author La clic ! <contact@laclic.fr> | |||
*/ | |||
class AssociationFilter | |||
{ | |||
use FilterTrait; | |||
public function buildProperty(FormBuilderInterface $builder, FieldDto $fieldDto, $options = array()) | |||
{ | |||
$targetEntity = $options['entity_dto']->getPropertyMetadata($fieldDto->getProperty())->get('targetEntity'); | |||
$classImplements = class_implements($targetEntity); | |||
$builder->add( | |||
$fieldDto->getProperty(), | |||
EntityType::class, | |||
array( | |||
'class' => $targetEntity, | |||
'placeholder' => '--', | |||
'query_builder' => function (EntityRepository $repo) use ($classImplements) { | |||
return $repo->createQueryBuilder('entity'); | |||
}, | |||
'required' => false, | |||
'attr' => array( | |||
'class' => 'select2 input-sm', | |||
'form' => 'filters-form', | |||
), | |||
) | |||
); | |||
} | |||
public function applyFilter(QueryBuilder $queryBuilder, string $fieldProperty, string $filteredValue = null) | |||
{ | |||
if ($filteredValue !== null) { | |||
$queryBuilder->andWhere('entity.'.$fieldProperty.' = :'.$fieldProperty.''); | |||
$queryBuilder->setParameter($fieldProperty, $filteredValue); | |||
/* //TODO Faut généraliser avec TreeInterface, ça ne doit pas être ici | |||
if ($field['property'] == 'productCategories') { | |||
$queryBuilder->andWhere(':' . $field['property'] . ' MEMBER OF entity.' . $field['property'] . ' OR product_categories.parent = :' . $field['property']); | |||
$queryBuilder->setParameter($field['property'], $filter); | |||
if ($field['type_options']['multiple']) { | |||
$queryBuilder->andWhere(':' . $field['property'] . ' MEMBER OF entity.' . $field['property'] . ''); | |||
} else { | |||
} | |||
if ($filter instanceof TreeInterface && $filter->getParent() == null) { | |||
$queryBuilder->setParameter($field['property'], array_merge(array($filter), $filter->getChildrens()->toArray())); | |||
} else { | |||
}*/ | |||
} | |||
} | |||
} |
@@ -0,0 +1,62 @@ | |||
<?php | |||
namespace Lc\SovBundle\Field\Filter; | |||
use Doctrine\ORM\QueryBuilder; | |||
use EasyCorp\Bundle\EasyAdminBundle\Dto\FieldDto; | |||
use Lc\SovBundle\Translation\TranslatorAdmin; | |||
use Symfony\Component\Form\Extension\Core\Type\ChoiceType; | |||
use Symfony\Component\Form\FormBuilderInterface; | |||
use function Symfony\Component\String\u; | |||
/** | |||
* @author La clic ! <contact@laclic.fr> | |||
*/ | |||
class CheckboxFilter | |||
{ | |||
use FilterTrait; | |||
public function buildProperty(FormBuilderInterface $builder, FieldDto $fieldDto, $options = array()) | |||
{ | |||
$builder->add($fieldDto->getProperty(), ChoiceType::class, array( | |||
'choices'=> array( | |||
'Oui' => 1, | |||
'Non' => 0, | |||
), | |||
'placeholder'=> '--', | |||
'required'=>false, | |||
'attr'=>array( | |||
'class'=> 'select2 input-sm', | |||
'form'=> 'filters-form' | |||
) | |||
)); | |||
} | |||
public function applyFilter(QueryBuilder $queryBuilder, string $fieldProperty, string $filteredValue= null) | |||
{ | |||
if ($filteredValue !== null) { | |||
if ($this->isRelationField($fieldProperty)) { | |||
$aliasRelation = $this->getFieldPropertyRelationAlias($fieldProperty); | |||
if (array_search($aliasRelation, $queryBuilder->getAllAliases()) === false) { | |||
$queryBuilder->innerJoin('entity.'.$aliasRelation, $aliasRelation); | |||
} | |||
$queryBuilder->andWhere( | |||
$fieldProperty.' = :'.$this->getFieldPropertySnake($fieldProperty).'' | |||
); | |||
$queryBuilder->setParameter( | |||
$this->getFieldPropertySnake($fieldProperty), | |||
'%'.$filteredValue.'%' | |||
); | |||
} else { | |||
$queryBuilder->andWhere( | |||
'entity.'.$fieldProperty.' = :'.$fieldProperty.'' | |||
); | |||
$queryBuilder->setParameter($fieldProperty, '%'.$filteredValue.'%'); | |||
} | |||
dump($queryBuilder); | |||
} | |||
} | |||
} |
@@ -0,0 +1,77 @@ | |||
<?php | |||
namespace Lc\SovBundle\Field\Filter; | |||
use Doctrine\ORM\QueryBuilder; | |||
use EasyCorp\Bundle\EasyAdminBundle\Dto\FieldDto; | |||
use Lc\SovBundle\Translation\TranslatorAdmin; | |||
use Symfony\Component\Form\Extension\Core\Type\ChoiceType; | |||
use Symfony\Component\Form\FormBuilderInterface; | |||
use function Symfony\Component\String\u; | |||
/** | |||
* @author La clic ! <contact@laclic.fr> | |||
*/ | |||
class ChoiceFilter | |||
{ | |||
use FilterTrait; | |||
protected $translatorAdmin; | |||
public function __construct(?TranslatorAdmin $translatorAdmin = null) | |||
{ | |||
$this->translatorAdmin = $translatorAdmin; | |||
} | |||
public function buildProperty(FormBuilderInterface $builder, FieldDto $fieldDto, $options = array()) | |||
{ | |||
$entity = new $options['entity_class']; | |||
$choicesFct = 'get'.u($fieldDto->getProperty())->title()->toString().'Choices'; | |||
if (method_exists($entity, $choicesFct)) { | |||
$builder->add( | |||
$fieldDto->getProperty(), | |||
ChoiceType::class, | |||
array( | |||
'required' => false, | |||
'choices' => $this->translatorAdmin->transChoices( | |||
$entity->$choicesFct(), | |||
$options['entity_name'], | |||
$fieldDto->getProperty() | |||
), | |||
'attr' => array( | |||
'class' => 'select2 input-sm', | |||
'form' => 'filters-form', | |||
), | |||
) | |||
); | |||
} | |||
} | |||
public function applyFilter(QueryBuilder $queryBuilder, string $fieldProperty, string $filteredValue = null) | |||
{ | |||
if ($filteredValue !== null) { | |||
if ($this->isRelationField($fieldProperty)) { | |||
$aliasRelation = $this->getFieldPropertyRelationAlias($fieldProperty); | |||
if (array_search($aliasRelation, $queryBuilder->getAllAliases()) === false) { | |||
$queryBuilder->innerJoin('entity.'.$aliasRelation, $aliasRelation); | |||
} | |||
$queryBuilder->andWhere( | |||
$fieldProperty.' LIKE :'.$this->getFieldPropertySnake($fieldProperty).'' | |||
); | |||
$queryBuilder->setParameter( | |||
$this->getFieldPropertySnake($fieldProperty), | |||
'%'.$filteredValue.'%' | |||
); | |||
} else { | |||
$queryBuilder->andWhere( | |||
'entity.'.$fieldProperty.' LIKE :'.$fieldProperty.'' | |||
); | |||
$queryBuilder->setParameter($fieldProperty, '%'.$filteredValue.'%'); | |||
} | |||
} | |||
} | |||
} |
@@ -0,0 +1,64 @@ | |||
<?php | |||
namespace Lc\SovBundle\Field\Filter; | |||
use Doctrine\ORM\QueryBuilder; | |||
use EasyCorp\Bundle\EasyAdminBundle\Dto\FieldDto; | |||
use Symfony\Component\Form\Extension\Core\Type\DateType; | |||
use Symfony\Component\Form\Extension\Core\Type\FormType; | |||
use Symfony\Component\Form\FormBuilderInterface; | |||
/** | |||
* @author La clic ! <contact@laclic.fr> | |||
*/ | |||
class DateFilter | |||
{ | |||
use FilterTrait; | |||
public function buildProperty(FormBuilderInterface $builder, FieldDto $fieldDto, $options = array()) | |||
{ | |||
$builder->add( | |||
$builder->create( | |||
str_replace('.', '_', $fieldDto->getProperty()), | |||
FormType::class, | |||
array('inherit_data' => true) | |||
) | |||
->add( | |||
'dateStart', | |||
DateType::class, | |||
array( | |||
'widget' => 'single_text', | |||
'required' => false, | |||
) | |||
) | |||
->add( | |||
'dateEnd', | |||
DateType::class, | |||
array( | |||
'widget' => 'single_text', | |||
'required' => false, | |||
) | |||
) | |||
); | |||
} | |||
public function applyFilter( | |||
QueryBuilder $queryBuilder, | |||
string $fieldProperty, | |||
\DateTime $dateStart = null, | |||
\DateTime $dateEnd = null | |||
) { | |||
if ($dateStart) { | |||
$queryBuilder->andWhere( | |||
'entity.'.$fieldProperty.' >= :dateStart' | |||
)->setParameter('dateStart', $dateStart); | |||
} | |||
if ($dateEnd) { | |||
$dateEnd->setTime(23, 59, 59); | |||
$queryBuilder->andWhere( | |||
'entity.'.$fieldProperty.' <= :dateEnd' | |||
)->setParameter('dateEnd', $dateEnd); | |||
} | |||
} | |||
} |
@@ -0,0 +1,175 @@ | |||
<?php | |||
namespace Lc\SovBundle\Field\Filter; | |||
use Doctrine\ORM\EntityManagerInterface; | |||
use Doctrine\ORM\QueryBuilder; | |||
use EasyCorp\Bundle\EasyAdminBundle\Config\Crud; | |||
use EasyCorp\Bundle\EasyAdminBundle\Contracts\Field\FieldInterface; | |||
use EasyCorp\Bundle\EasyAdminBundle\Dto\EntityDto; | |||
use EasyCorp\Bundle\EasyAdminBundle\Dto\FieldDto; | |||
use Symfony\Bridge\Doctrine\Form\Type\EntityType; | |||
use Symfony\Component\Form\Extension\Core\Type\CheckboxType; | |||
use Symfony\Component\Form\Extension\Core\Type\ChoiceType; | |||
use Symfony\Component\Form\Extension\Core\Type\DateTimeType; | |||
use Symfony\Component\Form\Extension\Core\Type\DateType; | |||
use Symfony\Component\Form\Extension\Core\Type\IntegerType; | |||
use Symfony\Component\Form\Extension\Core\Type\TextType; | |||
use Symfony\Component\Form\Form; | |||
use Symfony\Component\HttpFoundation\RequestStack; | |||
use Symfony\Component\HttpFoundation\Session\SessionInterface; | |||
/** | |||
* @author La clic ! <contact@laclic.fr> | |||
*/ | |||
class FilterManager | |||
{ | |||
protected $em; | |||
use FilterTrait; | |||
public function __construct(SessionInterface $session, EntityManagerInterface $entityManager) | |||
{ | |||
$this->session = $session; | |||
$this->em = $entityManager; | |||
} | |||
public function handleFiltersForm(QueryBuilder $queryBuilder, Form $filtersForm, $fields, EntityDto $entityDto) | |||
{ | |||
foreach ($fields as $field) { | |||
if ($field instanceof FieldInterface) { | |||
$fieldDto = $field->getAsDto(); | |||
} else { | |||
$fieldDto = $field; | |||
} | |||
if ($fieldDto->isDisplayedOn(Crud::PAGE_INDEX)) { | |||
if ($filtersForm->has($this->getFieldPropertySnake($fieldDto->getProperty()))) { | |||
if ($fieldDto->getFormType() === DateTimeType::class || $fieldDto->getFormType( | |||
) === DateType::class) { | |||
$filteredValue['dateStart'] = $this->getFilteredValue( | |||
$filtersForm, | |||
$entityDto->getFqcn(), | |||
$fieldDto->getProperty(), | |||
'dateStart' | |||
); | |||
$filteredValue['dateEnd'] = $this->getFilteredValue( | |||
$filtersForm, | |||
$entityDto->getFqcn(), | |||
$fieldDto->getProperty(), | |||
'dateEnd' | |||
); | |||
}else{ | |||
$filteredValue = $this->getFilteredValue( | |||
$filtersForm, | |||
$entityDto->getFqcn(), | |||
$fieldDto->getProperty() | |||
); | |||
} | |||
$this->applyFilter($queryBuilder, $fieldDto, $filteredValue); | |||
} | |||
} | |||
} | |||
} | |||
public function applyFilter(QueryBuilder $queryBuilder, FieldDto $fieldDto, $filteredValue) | |||
{ | |||
switch ($fieldDto->getFormType()) { | |||
case CheckboxType::class: | |||
$checkboxFilter = new CheckboxFilter(); | |||
$checkboxFilter->applyFilter($queryBuilder, $fieldDto->getProperty(), $filteredValue); | |||
break; | |||
case ChoiceType::class: | |||
$choiceFilter = new ChoiceFilter(); | |||
$choiceFilter->applyFilter($queryBuilder, $fieldDto->getProperty(), $filteredValue); | |||
break; | |||
case IntegerType::class: | |||
$integerFilter = new IntegerFilter(); | |||
$integerFilter->applyFilter($queryBuilder, $fieldDto->getProperty(), $filteredValue); | |||
break; | |||
case TextType::class: | |||
$textFilter = new TextFilter(); | |||
$textFilter->applyFilter($queryBuilder, $fieldDto->getProperty(), $filteredValue); | |||
break; | |||
case EntityType::class: | |||
$textFilter = new AssociationFilter(); | |||
$textFilter->applyFilter($queryBuilder, $fieldDto->getProperty(), $filteredValue); | |||
break; | |||
case DateTimeType::class: | |||
case DateType::class: | |||
$textFilter = new DateFilter(); | |||
$textFilter->applyFilter( | |||
$queryBuilder, | |||
$fieldDto->getProperty(), | |||
$filteredValue['dateStart'], | |||
$filteredValue['dateEnd'] | |||
); | |||
break; | |||
} | |||
} | |||
public function getFilteredValue( | |||
Form $filtersForm, | |||
string $entityFqcn, | |||
string $field, | |||
string $dateExtraField = null | |||
) { | |||
$field = $this->getFieldPropertySnake($field); | |||
$sessionParam = $entityFqcn.$field.$dateExtraField; | |||
$formField = $this->getFormField($filtersForm, $field, $dateExtraField); | |||
$value = $formField->getData(); | |||
//Il existe une valeur posté dans le formulaire | |||
if ($value !== null) { | |||
$this->session->set($sessionParam, $value); | |||
return $value; | |||
} | |||
//action reset | |||
if ($filtersForm->get('reset')->getData() == 'clearAll') { | |||
$this->session->remove($sessionParam); | |||
return null; | |||
} | |||
//Récupération des valeurs stocké en sessions si le forrmFilters n'a pas été posté | |||
if ($this->session->get($sessionParam) && !$filtersForm->isSubmitted() && $formField) { | |||
$value = $this->session->get($sessionParam); | |||
//Champ date | |||
if ($formField->getConfig()->getOption('input') == 'datetime') { | |||
$filtersForm->get($field)->get($dateExtraField)->setData($value); | |||
//Champ association | |||
} elseif ($formField->getConfig()->getOption('class')) { | |||
$valFormated = $this->em->getRepository( | |||
$formField->getConfig()->getOption('class') | |||
)->find($value); | |||
$filtersForm->get($field)->setData($valFormated); | |||
} else { | |||
//Champ noramux | |||
$filtersForm->get($field)->setData($value); | |||
} | |||
return $value; | |||
} | |||
} | |||
public | |||
function getFormField( | |||
Form $filtersForm, | |||
string $field, | |||
string $extraField = null | |||
): Form { | |||
if ($extraField) { | |||
return $filtersForm->get($field)->get($extraField); | |||
} else { | |||
return $filtersForm->get($field); | |||
} | |||
} | |||
} |
@@ -0,0 +1,37 @@ | |||
<?php | |||
namespace Lc\SovBundle\Field\Filter; | |||
/** | |||
* @author La clic ! <contact@laclic.fr> | |||
*/ | |||
trait FilterTrait | |||
{ | |||
public function getFieldPropertySnake(string $fieldName): string | |||
{ | |||
return str_replace('.', '_', $fieldName); | |||
} | |||
public function getFieldPropertyBase(string $fieldName): string | |||
{ | |||
return str_replace('_', '.', $fieldName); | |||
} | |||
public function isRelationField(string $fieldName, string $needle = "."): bool | |||
{ | |||
return strpos($fieldName, $needle) !== false; | |||
} | |||
public function getFieldPropertyWithoutRelation(string $fieldName, string $needle = '.'): string | |||
{ | |||
return substr($fieldName, strpos($fieldName, $needle) + 1); | |||
} | |||
public function getFieldPropertyRelationAlias(string $fieldName, string $needle = '.'): string | |||
{ | |||
return substr($fieldName, 0, strpos($fieldName, $needle)); | |||
} | |||
} |
@@ -0,0 +1,43 @@ | |||
<?php | |||
namespace Lc\SovBundle\Field\Filter; | |||
use Doctrine\ORM\QueryBuilder; | |||
use EasyCorp\Bundle\EasyAdminBundle\Dto\FieldDto; | |||
use Symfony\Component\Form\Extension\Core\Type\IntegerType; | |||
use Symfony\Component\Form\FormBuilderInterface; | |||
/** | |||
* @author La clic ! <contact@laclic.fr> | |||
*/ | |||
class IntegerFilter | |||
{ | |||
use FilterTrait; | |||
public function buildProperty(FormBuilderInterface $builder, FieldDto $fieldDto, $options = array()) | |||
{ | |||
$builder->add( | |||
str_replace('.', '_', $fieldDto->getProperty()), | |||
IntegerType::class, | |||
array( | |||
'required' => false, | |||
'attr' => array( | |||
'class' => ' input-sm', | |||
'form' => 'filters-form', | |||
), | |||
) | |||
); | |||
} | |||
public function applyFilter(QueryBuilder $queryBuilder, string $fieldProperty, string $filteredValue= null) | |||
{ | |||
if ($filteredValue !== null) { | |||
$queryBuilder->andWhere( | |||
'entity.'.$fieldProperty.' = :'.$fieldProperty.'' | |||
); | |||
$queryBuilder->setParameter($fieldProperty, $filteredValue); | |||
} | |||
} | |||
} |
@@ -0,0 +1,59 @@ | |||
<?php | |||
namespace Lc\SovBundle\Field\Filter; | |||
use Doctrine\ORM\QueryBuilder; | |||
use EasyCorp\Bundle\EasyAdminBundle\Dto\FieldDto; | |||
use Symfony\Component\Form\Extension\Core\Type\TextType; | |||
use Symfony\Component\Form\FormBuilderInterface; | |||
/** | |||
* @author La clic ! <contact@laclic.fr> | |||
*/ | |||
class TextFilter | |||
{ | |||
use FilterTrait; | |||
public function buildProperty(FormBuilderInterface $builder, FieldDto $fieldDto, $options = array()) | |||
{ | |||
$builder->add( | |||
str_replace('.', '_', $fieldDto->getProperty()), | |||
TextType::class, | |||
array( | |||
'required' => false, | |||
'attr' => array( | |||
'class' => ' input-sm', | |||
'form' => 'filters-form', | |||
), | |||
) | |||
); | |||
} | |||
public function applyFilter(QueryBuilder $queryBuilder, string $fieldProperty, string $filteredValue= null) | |||
{ | |||
if ($filteredValue !== null) { | |||
if ($this->isRelationField($fieldProperty)) { | |||
$aliasRelation = $this->getFieldPropertyRelationAlias($fieldProperty); | |||
if (array_search($aliasRelation, $queryBuilder->getAllAliases()) === false) { | |||
$queryBuilder->innerJoin('entity.'.$aliasRelation, $aliasRelation); | |||
} | |||
$queryBuilder->andWhere( | |||
$fieldProperty.' LIKE :'.$this->getFieldPropertySnake($fieldProperty).'' | |||
); | |||
$queryBuilder->setParameter( | |||
$this->getFieldPropertySnake($fieldProperty), | |||
'%'.$filteredValue.'%' | |||
); | |||
} else { | |||
$queryBuilder->andWhere( | |||
'entity.'.$fieldProperty.' LIKE :'.$fieldProperty.'' | |||
); | |||
$queryBuilder->setParameter($fieldProperty, '%'.$filteredValue.'%'); | |||
} | |||
} | |||
} | |||
} |
@@ -4,7 +4,7 @@ namespace Lc\SovBundle\Field; | |||
use EasyCorp\Bundle\EasyAdminBundle\Contracts\Field\FieldInterface; | |||
use EasyCorp\Bundle\EasyAdminBundle\Field\FieldTrait; | |||
use Lc\SovBundle\Form\Type\Crud\FileManagerType; | |||
use Lc\SovBundle\Form\Common\FileManagerType; | |||
use Symfony\Component\Form\Extension\Core\Type\CollectionType; | |||
@@ -4,8 +4,7 @@ namespace Lc\SovBundle\Field; | |||
use EasyCorp\Bundle\EasyAdminBundle\Contracts\Field\FieldInterface; | |||
use EasyCorp\Bundle\EasyAdminBundle\Field\FieldTrait; | |||
use Lc\SovBundle\Form\Type\Crud\FileManagerType; | |||
use Symfony\Component\Form\Extension\Core\Type\TextType; | |||
use Lc\SovBundle\Form\Common\FileManagerType; | |||
/** | |||
* @author La clic ! <contact@laclic.fr> |
@@ -4,36 +4,34 @@ namespace Lc\SovBundle\Field; | |||
use EasyCorp\Bundle\EasyAdminBundle\Contracts\Field\FieldInterface; | |||
use EasyCorp\Bundle\EasyAdminBundle\Field\FieldTrait; | |||
use Lc\SovBundle\Form\Type\FileManagerType; | |||
use Symfony\Component\Form\Extension\Core\Type\ChoiceType; | |||
use Symfony\Component\Form\Extension\Core\Type\TextType; | |||
/** | |||
* @author La clic ! <contact@laclic.fr> | |||
*/ | |||
final class StatusField implements FieldInterface | |||
{ | |||
use FieldTrait; | |||
public static function new(string $propertyName, ?string $label = null, bool $templateToggle = true): self | |||
{ | |||
$field = (new self()) | |||
->setProperty($propertyName) | |||
->setLabel($label) | |||
->setFormType(ChoiceType::class) | |||
->setFormTypeOption('expanded', true) | |||
->setFormTypeOption('multiple', false) | |||
->setFormTypeOption('choices', ['En ligne' => 1, 'Hors ligne' => 0]) | |||
->setCustomOption('toggle_label', 'En ligne'); | |||
$template = 'toggle.html.twig' ; | |||
if(!$templateToggle) { | |||
$template = 'status.html.twig' ; | |||
} | |||
$field->setTemplatePath('@LcSov/adminlte/crud/field/'.$template) ; | |||
return $field ; | |||
use FieldTrait; | |||
public static function new(string $propertyName, ?string $label = null, bool $templateToggle = true): self | |||
{ | |||
$field = (new self()) | |||
->setProperty($propertyName) | |||
->setLabel($label) | |||
->setFormType(ChoiceType::class) | |||
->setFormTypeOption('expanded', true) | |||
->setFormTypeOption('multiple', false) | |||
->setFormTypeOption('choices', ['En ligne' => 1, 'Hors ligne' => 0]) | |||
->setFormTypeOption('placeholder', false) | |||
->setCustomOption('toggle_label', 'En ligne'); | |||
$template = 'toggle.html.twig'; | |||
if (!$templateToggle) { | |||
$template = 'status.html.twig'; | |||
} | |||
$field->setTemplatePath('@LcSov/adminlte/crud/field/' . $template); | |||
return $field; | |||
} | |||
} |
@@ -0,0 +1,25 @@ | |||
<?php | |||
namespace Lc\SovBundle\Field; | |||
use EasyCorp\Bundle\EasyAdminBundle\Contracts\Field\FieldInterface; | |||
use EasyCorp\Bundle\EasyAdminBundle\Field\FieldTrait; | |||
use Symfony\Component\Form\Extension\Core\Type\CheckboxType; | |||
/** | |||
* @author La clic ! <contact@laclic.fr> | |||
*/ | |||
final class ToggleField implements FieldInterface | |||
{ | |||
use FieldTrait; | |||
public static function new(string $propertyName, ?string $label = null): self | |||
{ | |||
return (new self()) | |||
->setProperty($propertyName) | |||
->setLabel($label) | |||
->setTemplatePath('@LcSov/adminlte/crud/field/toggle.html.twig') | |||
->setFormType(CheckboxType::class); | |||
} | |||
} |
@@ -1,6 +1,6 @@ | |||
<?php | |||
namespace Lc\SovBundle\Form\Type\Crud; | |||
namespace Lc\SovBundle\Form\Common; | |||
use EasyCorp\Bundle\EasyAdminBundle\Form\Type\EaFormPanelType; | |||
@@ -22,20 +22,25 @@ class CrudFormType extends AbstractType | |||
protected $parent; | |||
protected $doctrineOrmTypeGuesser; | |||
public function __construct(DoctrineOrmTypeGuesser $doctrineOrmTypeGuesser, \EasyCorp\Bundle\EasyAdminBundle\Form\Type\CrudFormType $crudFormType) | |||
{ | |||
public function __construct( | |||
DoctrineOrmTypeGuesser $doctrineOrmTypeGuesser, | |||
\EasyCorp\Bundle\EasyAdminBundle\Form\Type\CrudFormType $crudFormType | |||
) { | |||
$this->parent = $crudFormType; | |||
$this->doctrineOrmTypeGuesser = $doctrineOrmTypeGuesser; | |||
} | |||
public function buildForm(FormBuilderInterface $builder, array $options) | |||
{ | |||
$this->parent->buildForm($builder, $options); | |||
$entityDto = $options['entityDto']; | |||
$formPanels=[]; | |||
$formPanels = []; | |||
$currentFormPanel = 0; | |||
foreach ($entityDto->getFields() as $fieldDto) { | |||
if (null === $formFieldType = $fieldDto->getFormType()) { | |||
$guessType = $this->doctrineOrmTypeGuesser->guessType($entityDto->getFqcn(), $fieldDto->getProperty()); | |||
$formFieldType = $guessType->getType(); | |||
@@ -50,7 +55,7 @@ class CrudFormType extends AbstractType | |||
'help' => $fieldDto->getHelp(), | |||
'css_class' => $fieldDto->getCssClass(), | |||
]; | |||
foreach($fieldDto->getCustomOptions()->all() as $customOptionKey=> $customOption){ | |||
foreach ($fieldDto->getCustomOptions()->all() as $customOptionKey => $customOption) { | |||
$formPanels[$currentFormPanel][$customOptionKey] = $customOption; | |||
} | |||
continue; | |||
@@ -60,17 +65,20 @@ class CrudFormType extends AbstractType | |||
//$this->niche->buildForm($builder, $options); | |||
} | |||
public function finishView(FormView $view, FormInterface $form, array $options){ | |||
public function finishView(FormView $view, FormInterface $form, array $options) | |||
{ | |||
$this->parent->finishView($view, $form, $options); | |||
} | |||
public function configureOptions(OptionsResolver $resolver){ | |||
$this->parent->configureOptions($resolver); | |||
public function configureOptions(OptionsResolver $resolver) | |||
{ | |||
$this->parent->configureOptions($resolver); | |||
} | |||
public function getBlockPrefix(){ | |||
public function getBlockPrefix() | |||
{ | |||
return $this->parent->getBlockPrefix(); | |||
} | |||
} |
@@ -1,6 +1,6 @@ | |||
<?php | |||
namespace Lc\SovBundle\Form\Type\Crud; | |||
namespace Lc\SovBundle\Form\Common; | |||
use Lc\SovBundle\DataTransformer\FileManagerTypeToDataTransformer; | |||
use Lc\SovBundle\Entity\File\File; |
@@ -0,0 +1,140 @@ | |||
<?php | |||
namespace Lc\SovBundle\Form\Common; | |||
use Doctrine\ORM\EntityManagerInterface; | |||
use Doctrine\ORM\EntityRepository; | |||
use EasyCorp\Bundle\EasyAdminBundle\Config\Crud; | |||
use EasyCorp\Bundle\EasyAdminBundle\Contracts\Field\FieldInterface; | |||
use Lc\SovBundle\Field\Filter\AssociationFilter; | |||
use Lc\SovBundle\Field\Filter\CheckboxFilter; | |||
use Lc\SovBundle\Field\Filter\ChoiceFilter; | |||
use Lc\SovBundle\Field\Filter\DateFilter; | |||
use Lc\SovBundle\Field\Filter\FilterManager; | |||
use Lc\SovBundle\Field\Filter\IntegerFilter; | |||
use Lc\SovBundle\Field\Filter\TextFilter; | |||
use Lc\SovBundle\Translation\TranslatorAdmin; | |||
use Symfony\Bridge\Doctrine\Form\Type\EntityType; | |||
use Symfony\Component\Form\AbstractType; | |||
use Symfony\Component\Form\Extension\Core\Type\ButtonType; | |||
use Symfony\Component\Form\Extension\Core\Type\CheckboxType; | |||
use Symfony\Component\Form\Extension\Core\Type\ChoiceType; | |||
use Symfony\Component\Form\Extension\Core\Type\DateTimeType; | |||
use Symfony\Component\Form\Extension\Core\Type\DateType; | |||
use Symfony\Component\Form\Extension\Core\Type\FormType; | |||
use Symfony\Component\Form\Extension\Core\Type\HiddenType; | |||
use Symfony\Component\Form\Extension\Core\Type\IntegerType; | |||
use Symfony\Component\Form\Extension\Core\Type\SubmitType; | |||
use Symfony\Component\Form\Extension\Core\Type\TextType; | |||
use Symfony\Component\Form\FormBuilderInterface; | |||
use Symfony\Component\OptionsResolver\OptionsResolver; | |||
use Symfony\Contracts\Translation\TranslatorInterface; | |||
use function Symfony\Component\String\u; | |||
class FiltersFormType extends AbstractType | |||
{ | |||
protected $translatorAdmin; | |||
public function __construct(TranslatorAdmin $translatorAdmin) | |||
{ | |||
$this->translatorAdmin = $translatorAdmin; | |||
} | |||
public function buildForm(FormBuilderInterface $builder, array $options) | |||
{ | |||
foreach ($options['fields'] as $field) { | |||
if ($field instanceof FieldInterface) { | |||
$fieldDto = $field->getAsDto(); | |||
} else { | |||
$fieldDto = $field; | |||
} | |||
if ($fieldDto->isDisplayedOn(Crud::PAGE_INDEX)) { | |||
switch ($fieldDto->getFormType()) { | |||
case CheckboxType::class: | |||
$checkboxFilter = new CheckboxFilter(); | |||
$checkboxFilter->buildProperty($builder, $fieldDto); | |||
break; | |||
case ChoiceType::class: | |||
$choiceFilter = new ChoiceFilter($this->translatorAdmin); | |||
$choiceFilter->buildProperty($builder, $fieldDto, $options); | |||
break; | |||
case IntegerType::class: | |||
$integerFilter = new IntegerFilter(); | |||
$integerFilter->buildProperty($builder, $fieldDto); | |||
break; | |||
case TextType::class: | |||
$textFilter = new TextFilter(); | |||
$textFilter->buildProperty($builder, $fieldDto); | |||
break; | |||
case DateTimeType::class: | |||
case DateType::class: | |||
$textFilter = new DateFilter(); | |||
$textFilter->buildProperty($builder, $fieldDto); | |||
break; | |||
case EntityType::class: | |||
$associationFilter = new AssociationFilter(); | |||
$associationFilter->buildProperty($builder, $fieldDto, $options); | |||
break; | |||
case 'dateinterval': | |||
break; | |||
case 'float': | |||
break; | |||
} | |||
} | |||
} | |||
$builder->add( | |||
'action_apply', | |||
SubmitType::class, | |||
array( | |||
'label_html'=> true, | |||
'label'=> '<i class="fa fa-search"></i>', | |||
'attr' => array( | |||
'class' => 'btn btn-sm btn-info', | |||
'form' => 'filters-form', | |||
'data-toggle'=>"tooltip", | |||
'title'=> $this->translatorAdmin->transAction("apply"), | |||
'aria-label'=> $this->translatorAdmin->transAction("apply") | |||
), | |||
) | |||
); | |||
$builder->add( | |||
'action_reset', | |||
ButtonType::class, | |||
array( | |||
'label_html'=> true, | |||
'label'=> '<i class="fa fa-eraser"></i>', | |||
'attr' => array( | |||
'class' => 'btn btn-sm btn-warning lc-reset-filters', | |||
'form' => 'filters-form', | |||
'data-toggle'=>"tooltip", | |||
'title'=> $this->translatorAdmin->transAction("reset"), | |||
'aria-label'=> $this->translatorAdmin->transAction("reset") | |||
), | |||
) | |||
); | |||
$builder->add('reset', HiddenType::class); | |||
} | |||
public function configureOptions(OptionsResolver $resolver) | |||
{ | |||
$resolver->setDefaults( | |||
[ | |||
'label' => false, | |||
'csrf_protection' => false, | |||
'entity_dto' => null, | |||
//'translation_domain' => 'lcshop', | |||
'fields' => false, | |||
'entity_name' => false, | |||
'entity_class' => false, | |||
//'entityClass' => false | |||
] | |||
); | |||
} | |||
} |
@@ -1,6 +1,6 @@ | |||
<?php | |||
namespace Lc\SovBundle\Form\Type\Crud; | |||
namespace Lc\SovBundle\Form\Common; | |||
use Symfony\Component\Form\AbstractType; |
@@ -0,0 +1,89 @@ | |||
<?php | |||
namespace Lc\SovBundle\Form\Reminder; | |||
use Lc\SovBundle\Model\Reminder\ReminderInterface; | |||
use Lc\SovBundle\Model\User\UserInterface; | |||
use Symfony\Bridge\Doctrine\Form\Type\EntityType; | |||
use Symfony\Component\Form\Extension\Core\Type\DateType; | |||
use Symfony\Component\Form\Extension\Core\Type\HiddenType; | |||
use Symfony\Component\Form\Extension\Core\Type\TextareaType; | |||
use Symfony\Component\Form\Extension\Core\Type\TextType; | |||
use Doctrine\ORM\EntityManagerInterface; | |||
use Symfony\Component\Form\AbstractType; | |||
use Symfony\Component\Form\FormBuilderInterface; | |||
use Symfony\Component\OptionsResolver\OptionsResolver; | |||
class ReminderAdminFormType extends AbstractType | |||
{ | |||
protected $entityManager; | |||
public function __construct(EntityManagerInterface $entityManager) | |||
{ | |||
$this->entityManager = $entityManager; | |||
} | |||
public function buildForm(FormBuilderInterface $builder, array $options) | |||
{ | |||
$userClass = $this->entityManager->getEntityName(UserInterface::class); | |||
$userRepo = $this->entityManager->getRepository(UserInterface::class); | |||
$builder | |||
->add('title', TextType::class, ['label' => 'Titre']) | |||
->add( | |||
'description', | |||
TextareaType::class, | |||
array( | |||
'required' => false | |||
) | |||
) | |||
->add( | |||
'crudAction', | |||
HiddenType::class, | |||
array( | |||
'required' => false | |||
) | |||
) | |||
->add( | |||
'crudControllerFqcn', | |||
HiddenType::class, | |||
array( | |||
'required' => false | |||
) | |||
) | |||
->add( | |||
'entityId', | |||
HiddenType::class, | |||
array( | |||
'required' => false | |||
) | |||
) | |||
->add( | |||
'users', | |||
EntityType::class, | |||
array( | |||
'class' => $userClass, | |||
'choices' => $userRepo->findByRole('ROLE_ADMIN'), | |||
'required' => false, | |||
'multiple' => true, | |||
'expanded' => false | |||
) | |||
) | |||
->add( | |||
'dateReminder', | |||
DateType::class, | |||
array( | |||
'required' => false, | |||
'widget' => 'single_text', | |||
) | |||
); | |||
} | |||
public function configureOptions(OptionsResolver $resolver) | |||
{ | |||
$resolver->setDefaults( | |||
[ | |||
'data_class' => $this->entityManager->getEntityName(ReminderInterface::class) | |||
] | |||
); | |||
} | |||
} |
@@ -0,0 +1,117 @@ | |||
<?php | |||
namespace Lc\SovBundle\Form\Setting; | |||
use FOS\CKEditorBundle\Form\Type\CKEditorType; | |||
use Lc\SovBundle\Definition\SiteSettingDefinitionInterface; | |||
use Lc\SovBundle\Form\Common\FileManagerType; | |||
use Symfony\Component\Form\Extension\Core\Type\ChoiceType; | |||
use Symfony\Component\Form\Extension\Core\Type\DateType; | |||
use Symfony\Component\Form\Extension\Core\Type\TextareaType; | |||
use Symfony\Component\Form\Extension\Core\Type\TextType; | |||
use Doctrine\ORM\EntityManagerInterface; | |||
use Symfony\Component\Form\AbstractType; | |||
use Symfony\Component\Form\Extension\Core\Type\TimeType; | |||
abstract class BaseSettingType extends AbstractType | |||
{ | |||
protected $em; | |||
protected $settingDefinition; | |||
public function __construct( | |||
EntityManagerInterface $entityManager, | |||
SiteSettingDefinitionInterface $settingDefinition | |||
) { | |||
$this->em = $entityManager; | |||
$this->settingDefinition = $settingDefinition; | |||
} | |||
public function buildFormSetting($label, $form, $settingDefinition, $settingEntity) | |||
{ | |||
$settingName = $settingEntity->getName(); | |||
$setting = $settingDefinition->getSettingByName($settingName); | |||
$settingType = $settingDefinition->getSettingType($settingName); | |||
if ($settingType == 'text') { | |||
$form->add( | |||
'text', | |||
TextType::class, | |||
[ | |||
'label' => $label | |||
] | |||
); | |||
} elseif ($settingType == 'textarea') { | |||
$form->add( | |||
'text', | |||
TextareaType::class, | |||
[ | |||
'label' => $label | |||
] | |||
); | |||
} elseif ($settingType == 'textarea_advanced') { | |||
$form->add( | |||
'text', | |||
CKEditorType::class, | |||
[ | |||
'label' => $label | |||
] | |||
); | |||
} elseif ($settingType == 'select') { | |||
$form->add( | |||
'text', | |||
ChoiceType::class, | |||
[ | |||
'label' => $label, | |||
'expanded' => false, | |||
'multiple' => false, | |||
'placeholder' => false, | |||
'choices' => $setting['choices'] | |||
] | |||
); | |||
} elseif ($settingType == 'radio') { | |||
$form->add( | |||
'text', | |||
ChoiceType::class, | |||
[ | |||
'label' => $label, | |||
'expanded' => true, | |||
'multiple' => false, | |||
'placeholder' => false, | |||
'choices' => $setting['choices'] | |||
] | |||
); | |||
} elseif ($settingType == 'date') { | |||
$form->add( | |||
'date', | |||
DateType::class, | |||
[ | |||
'label' => $label, | |||
'widget' => 'single_text', | |||
] | |||
); | |||
} elseif ($settingType == 'time') { | |||
$form->add( | |||
'date', | |||
TimeType::class, | |||
[ | |||
'label' => $label, | |||
'input' => 'datetime', | |||
'widget' => 'single_text', | |||
] | |||
); | |||
} elseif ($settingType == 'file' || $settingType == 'image') { | |||
$form->add( | |||
'file', | |||
FileManagerType::class, | |||
[ | |||
'label' => $label, | |||
'attr' => [ | |||
'type' => $settingType | |||
] | |||
] | |||
); | |||
} | |||
} | |||
} | |||