Compare commits
137 commits
Author | SHA1 | Date | |
---|---|---|---|
Simon Vieille | 26cbaa8469 | ||
Simon Vieille | 7897bafcc2 | ||
Simon Vieille | 63a8a60e2d | ||
Simon Vieille | d01e9d618b | ||
Simon Vieille | 96347a1730 | ||
Simon Vieille | aeb0e6c109 | ||
Simon Vieille | 64258a2d8c | ||
Simon Vieille | 70329ceeda | ||
Simon Vieille | 1adb1ebe2b | ||
Simon Vieille | f57cc8e4d6 | ||
Simon Vieille | b21967028e | ||
Simon Vieille | 5b22851674 | ||
Simon Vieille | 4082bb171a | ||
Simon Vieille | dc19617fb1 | ||
Simon Vieille | dbd2036fb0 | ||
Simon Vieille | 8e2566abc8 | ||
Simon Vieille | 66e1a9c87f | ||
Simon Vieille | 6709c0a303 | ||
Simon Vieille | 614ae40901 | ||
Simon Vieille | 430bff9433 | ||
Simon Vieille | 6441da8a27 | ||
Simon Vieille | 801e3317e7 | ||
Simon Vieille | f7604d2a45 | ||
Simon Vieille | 8a632a1b14 | ||
Simon Vieille | 4701090134 | ||
Simon Vieille | c40c7e3362 | ||
Simon Vieille | 8edbf0cc08 | ||
Simon Vieille | 175321bc2d | ||
Simon Vieille | 5d6531d197 | ||
Simon Vieille | 90603f62e0 | ||
Simon Vieille | 053f4aa5b8 | ||
Simon Vieille | 79754d45c1 | ||
Simon Vieille | c98ea50f30 | ||
Simon Vieille | 0f1bc761b2 | ||
Simon Vieille | 50dbb07314 | ||
Simon Vieille | 72e783f865 | ||
Simon Vieille | ee28c9abb7 | ||
2bd6836a7f | |||
6f961ba79b | |||
e095fc4197 | |||
6736f94eea | |||
93a1e7811d | |||
a0027c0b69 | |||
498c71081d | |||
8713b401f9 | |||
1463f43298 | |||
b89e036c49 | |||
1d0b657c83 | |||
0cadf28738 | |||
ede8d4fdcb | |||
5c3f2ab1e7 | |||
c1eb277a6a | |||
d3f27d97ad | |||
5e392d469a | |||
67f79083ef | |||
b9b07c1409 | |||
521ed5ce64 | |||
dda43ef3cc | |||
c65cc26be8 | |||
2f884df602 | |||
8979fc5beb | |||
bd663838f6 | |||
177b23365b | |||
645ae700d4 | |||
7614c24012 | |||
1f2edf183b | |||
28a4f63640 | |||
7fceefa6d3 | |||
a08c62229d | |||
f97f1dfedf | |||
45b3f6bb80 | |||
21ee41ff29 | |||
8d5de79192 | |||
212afe2775 | |||
16dd0d5744 | |||
9957523c59 | |||
688f66e94e | |||
c9b997e75d | |||
374db9117f | |||
4048152a8e | |||
4385e7a525 | |||
5d3999f766 | |||
03c0d6cfd2 | |||
290a4750bc | |||
7d647d3bb4 | |||
d637c44e5c | |||
19d26e6bd0 | |||
109584d933 | |||
c3209c68dd | |||
4a5b67dd93 | |||
4573a8d31e | |||
405909a4e7 | |||
2b3e2027c9 | |||
76b25f3bca | |||
ca25210d1c | |||
0ab960ed0a | |||
8e0a7f178b | |||
200dd0b8d6 | |||
bd4338bb2d | |||
64b524b04e | |||
6a5c5d899f | |||
b38fe0fe00 | |||
d21ab30ebe | |||
a96a6377d5 | |||
946a421900 | |||
f7eb5b0b49 | |||
0dadc670d9 | |||
4a0b13e6e3 | |||
1936b366df | |||
4541bbfb8a | |||
f3674ad4e0 | |||
ddf1fecc90 | |||
0c61cb9355 | |||
fc1a1c617e | |||
bea2d1cc9f | |||
4bf6b048c3 | |||
81194a1d67 | |||
10221591c2 | |||
231742eb0d | |||
f1d956ee5c | |||
5de35c3408 | |||
f144760085 | |||
e2c9ecb941 | |||
f9a20716a0 | |||
b107f077de | |||
2729b38fd8 | |||
baeecc0f7f | |||
8667188675 | |||
895d5065ca | |||
c688cc0552 | |||
c0340ec5a9 | |||
650ea3ede0 | |||
497ee2f027 | |||
8b13d37e71 | |||
3219ba47aa | |||
7ca8a4aa04 | |||
7ba417a03e |
94
CHANGELOG.md
94
CHANGELOG.md
|
@ -1,5 +1,99 @@
|
|||
## [Unreleased]
|
||||
|
||||
### Added
|
||||
* allow to use `window.tinymceModes` to add or override tinymce modes
|
||||
* add border color on tinymce editor
|
||||
### Fixed
|
||||
* fix default crud sort
|
||||
* fix hidden save button in file manager
|
||||
* fix template of CrudController (maker)
|
||||
* fix undefined `window.tinymce.murph`
|
||||
|
||||
## [v1.24.1] - 2024-02-01
|
||||
### Fixed
|
||||
* update Murph version constant
|
||||
|
||||
## [v1.24.0] - 2024-01-27
|
||||
### Added
|
||||
* add CSS class `no-wrap`
|
||||
* copy the pager of the CRUD at the bottom of the list
|
||||
### Fixed
|
||||
* fix an issue with the file manager when editing an item opened in a modal
|
||||
* fix type casting in slugifier
|
||||
|
||||
## [v1.23.0] - 2023-11-01
|
||||
### Added
|
||||
* allow to define templates show before and after a murph collection item
|
||||
* add global batch actions
|
||||
* add constraint `Length` in forms
|
||||
* add sass classes to mange with of elements
|
||||
* set searchFields option on jschoice manager (search on labels)
|
||||
### Changed
|
||||
* refactor services using constructor property promotions
|
||||
* remove twig in the mail notifier service
|
||||
* change pills colors
|
||||
* change border colors of inputs when focused
|
||||
* change colors on js-choices element
|
||||
### Fixed
|
||||
* fix regression on crud sorting
|
||||
* fix test in RepositoryQuery::addForcedFilterHandler
|
||||
* remove parameter $option on CrudConfiguration::setForm and fix CrudController make template
|
||||
* fix the aspect of the actions's column in the crud
|
||||
|
||||
## [v1.22.0] - 2023-09-28
|
||||
### Added
|
||||
* add new options in BooleanField: `toggle|checkbox_class_when_true` and `toggle|checkbox_class_when_false`
|
||||
* add `count` method in repository query
|
||||
* add `addForcedFilterHandler` method in repository query
|
||||
* add `inline_form_validation` option to validate inline forms with custom algo
|
||||
* add crud sorting parameters in the session
|
||||
* add flush option in the entity manager on create, update, remove, and persist methods
|
||||
|
||||
## [1.21.1] - 2023-08-17
|
||||
### Added
|
||||
* add form error handle in inline edit action and refill the form using the previous request content
|
||||
* add form error handle in ssettings actions and refill the form using the previous request content
|
||||
### Fixed
|
||||
* fix tinymce reload when modal is closed and reopened
|
||||
* fix modal hiding when a file is successfuly uploaded in the file manager
|
||||
|
||||
## [1.21.0] - 2023-08-11
|
||||
### Added
|
||||
* allow to use array syntax in string builder filter
|
||||
* add color property in Navigation
|
||||
* add badge with navigation color in admin views
|
||||
* add `default_value` option in crud fields
|
||||
* add `display` option in BooleanField
|
||||
* add associated nodes in page form
|
||||
### Fixed
|
||||
* fix routes in the global settings controller
|
||||
|
||||
## [1.20.0] - 2023-07-27
|
||||
### Added
|
||||
* enable double click on cruds
|
||||
* add block class name for the choice type in the page maker
|
||||
* update file details view on the file manager
|
||||
* add form options in the crud filter action
|
||||
* add trans filter in inline form modal title
|
||||
* add setter to define all fields in a defined context
|
||||
* add filename generator setter in FileUploadHandler
|
||||
* add variable for the sidebar size
|
||||
* add twig block to override defaults actions in crud index template
|
||||
* add option to remove iterable values and/or specifics keys in the twig toArray function
|
||||
* add boolean field for CRUD
|
||||
* add context variable in each controllers to simplify overrides
|
||||
* core.site.name and core.site.logo are not longer required
|
||||
* add default templates when a crud is generated
|
||||
* add boolean 'is_disabled' in the menu item template options
|
||||
### Fixed
|
||||
* fix filemanager date ordering
|
||||
* fix maker CrudController template: remove bad pasted code
|
||||
* fix redirect listener: use boolean instead of integer
|
||||
* fix responsive of account edit template
|
||||
* fix collection widget: allow_add/allow_delete and prototype
|
||||
### Changed
|
||||
* user admin routes are defined in core, custom controller is not required
|
||||
|
||||
## [1.19.0] - 2023-04-15
|
||||
### Added
|
||||
* feat(page): forms for metas, opengraph and extra informations can be removed
|
||||
|
|
|
@ -10,14 +10,12 @@ namespace App\Core\Ab;
|
|||
class AbTest implements AbTestInterface
|
||||
{
|
||||
protected $results;
|
||||
protected string $name;
|
||||
protected array $variations = [];
|
||||
protected array $probabilities = [];
|
||||
protected int $duration = 3600 * 24;
|
||||
|
||||
public function __construct(string $name)
|
||||
public function __construct(protected string $name)
|
||||
{
|
||||
$this->name = $name;
|
||||
}
|
||||
|
||||
public function getName(): string
|
||||
|
|
|
@ -13,18 +13,16 @@ use App\Core\Repository\Analytic\ViewRepositoryQuery;
|
|||
*/
|
||||
class DateRangeAnalytic
|
||||
{
|
||||
protected ViewRepositoryQuery $viewQuery;
|
||||
protected RefererRepositoryQuery $refererQuery;
|
||||
protected ?Node $node;
|
||||
protected ?\DateTime $from;
|
||||
protected ?\DateTime $to;
|
||||
protected bool $reload = true;
|
||||
protected array $cache = [];
|
||||
|
||||
public function __construct(ViewRepositoryQuery $viewQuery, RefererRepositoryQuery $refererQuery)
|
||||
{
|
||||
$this->viewQuery = $viewQuery;
|
||||
$this->refererQuery = $refererQuery;
|
||||
public function __construct(
|
||||
protected ViewRepositoryQuery $viewQuery,
|
||||
protected RefererRepositoryQuery $refererQuery
|
||||
) {
|
||||
}
|
||||
|
||||
public function getViews(): array
|
||||
|
@ -83,7 +81,7 @@ class DateRangeAnalytic
|
|||
$datas[$index]['mobileViews'] += $entity->getMobileViews();
|
||||
}
|
||||
|
||||
uasort($datas, function($a, $b) {
|
||||
uasort($datas, function ($a, $b) {
|
||||
if ($a['views'] > $b['views']) {
|
||||
return -1;
|
||||
}
|
||||
|
@ -130,7 +128,7 @@ class DateRangeAnalytic
|
|||
$datas[$index]['uris'][$path] += $entity->getViews();
|
||||
}
|
||||
|
||||
uasort($datas, function($a, $b) {
|
||||
uasort($datas, function ($a, $b) {
|
||||
if ($a['views'] > $b['views']) {
|
||||
return -1;
|
||||
}
|
||||
|
|
|
@ -10,16 +10,10 @@ namespace App\Core\Annotation;
|
|||
#[\Attribute]
|
||||
class UrlGenerator
|
||||
{
|
||||
public string $service;
|
||||
|
||||
public string $method;
|
||||
|
||||
public array $options = [];
|
||||
|
||||
public function __construct(string $service, string $method, array $options = [])
|
||||
{
|
||||
$this->service = $service;
|
||||
$this->method = $method;
|
||||
$this->options = $options;
|
||||
public function __construct(
|
||||
public string $service,
|
||||
public string $method,
|
||||
public array $options = []
|
||||
) {
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,20 +23,12 @@ class LoginFormAuthenticator extends AbstractFormLoginAuthenticator
|
|||
{
|
||||
use TargetPathTrait;
|
||||
|
||||
private EntityManagerInterface $entityManager;
|
||||
|
||||
private UrlGeneratorInterface $urlGenerator;
|
||||
|
||||
private CsrfTokenManagerInterface $csrfTokenManager;
|
||||
|
||||
private UserPasswordEncoderInterface $passwordEncoder;
|
||||
|
||||
public function __construct(EntityManagerInterface $entityManager, UrlGeneratorInterface $urlGenerator, CsrfTokenManagerInterface $csrfTokenManager, UserPasswordEncoderInterface $passwordEncoder)
|
||||
{
|
||||
$this->entityManager = $entityManager;
|
||||
$this->urlGenerator = $urlGenerator;
|
||||
$this->csrfTokenManager = $csrfTokenManager;
|
||||
$this->passwordEncoder = $passwordEncoder;
|
||||
public function __construct(
|
||||
private EntityManagerInterface $entityManager,
|
||||
private UrlGeneratorInterface $urlGenerator,
|
||||
private CsrfTokenManagerInterface $csrfTokenManager,
|
||||
private UserPasswordEncoderInterface $passwordEncoder
|
||||
) {
|
||||
}
|
||||
|
||||
public function supports(Request $request)
|
||||
|
|
|
@ -12,8 +12,8 @@
|
|||
namespace App\Core\Bundle;
|
||||
|
||||
use App\Core\DependencyInjection\CoreExtension;
|
||||
use Symfony\Component\HttpKernel\Bundle\Bundle;
|
||||
use Symfony\Component\DependencyInjection\Extension\ExtensionInterface;
|
||||
use Symfony\Component\HttpKernel\Bundle\Bundle;
|
||||
|
||||
class CoreBundle extends Bundle
|
||||
{
|
||||
|
|
|
@ -5,13 +5,13 @@ namespace App\Core\Cache;
|
|||
use Symfony\Bundle\FrameworkBundle\Console\Application;
|
||||
use Symfony\Component\Console\Input\ArrayInput;
|
||||
use Symfony\Component\Console\Output\BufferedOutput;
|
||||
use Symfony\Component\Finder\Finder;
|
||||
use Symfony\Component\HttpKernel\KernelInterface;
|
||||
use Symfony\Contracts\HttpClient\HttpClientInterface;
|
||||
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
|
||||
use Symfony\Component\HttpClient\Exception\ClientException;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Finder\Finder;
|
||||
use Symfony\Component\HttpClient\Exception\ClientException;
|
||||
use Symfony\Component\HttpClient\Exception\TransportException;
|
||||
use Symfony\Component\HttpKernel\KernelInterface;
|
||||
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
|
||||
use Symfony\Contracts\HttpClient\HttpClientInterface;
|
||||
|
||||
/**
|
||||
* class SymfonyCacheManager.
|
||||
|
@ -20,15 +20,11 @@ use Symfony\Component\HttpClient\Exception\TransportException;
|
|||
*/
|
||||
class SymfonyCacheManager
|
||||
{
|
||||
protected KernelInterface $kernel;
|
||||
protected HttpClientInterface $httpClient;
|
||||
protected UrlGeneratorInterface $urlGenerator;
|
||||
|
||||
public function __construct(KernelInterface $kernel, HttpClientInterface $httpClient, UrlGeneratorInterface $urlGenerator)
|
||||
{
|
||||
$this->kernel = $kernel;
|
||||
$this->httpClient = $httpClient;
|
||||
$this->urlGenerator = $urlGenerator;
|
||||
public function __construct(
|
||||
protected KernelInterface $kernel,
|
||||
protected HttpClientInterface $httpClient,
|
||||
protected UrlGeneratorInterface $urlGenerator
|
||||
) {
|
||||
}
|
||||
|
||||
public function cleanRouting()
|
||||
|
|
|
@ -18,19 +18,12 @@ class UserCreateCommand extends Command
|
|||
{
|
||||
protected static $defaultName = 'murph:user:create';
|
||||
protected static $defaultDescription = 'Creates a user';
|
||||
protected UserFactory $userFactory;
|
||||
protected EntityManager $entityManager;
|
||||
protected TokenGeneratorInterface $tokenGenerator;
|
||||
|
||||
public function __construct(
|
||||
UserFactory $userFactory,
|
||||
EntityManager $entityManager,
|
||||
TokenGeneratorInterface $tokenGenerator
|
||||
protected UserFactory $userFactory,
|
||||
protected EntityManager $entityManager,
|
||||
protected TokenGeneratorInterface $tokenGenerator
|
||||
) {
|
||||
$this->userFactory = $userFactory;
|
||||
$this->entityManager = $entityManager;
|
||||
$this->tokenGenerator = $tokenGenerator;
|
||||
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
|
|
|
@ -26,7 +26,7 @@ abstract class CrudController extends AdminController
|
|||
|
||||
abstract protected function getConfiguration(): CrudConfiguration;
|
||||
|
||||
protected function doIndex(int $page, RepositoryQuery $query, Request $request, Session $session): Response
|
||||
protected function doIndex(int $page, RepositoryQuery $query, Request $request, Session $session, string $context = 'index'): Response
|
||||
{
|
||||
$configuration = $this->getConfiguration();
|
||||
|
||||
|
@ -35,13 +35,14 @@ abstract class CrudController extends AdminController
|
|||
|
||||
$pager = $query
|
||||
->usefilters($this->filters)
|
||||
->paginate($page, $configuration->getmaxperpage('index'))
|
||||
->paginate($page, $configuration->getMaxPerPage($context))
|
||||
;
|
||||
|
||||
return $this->render($this->getConfiguration()->getView('index'), [
|
||||
return $this->render($this->getConfiguration()->getView($context), [
|
||||
'configuration' => $configuration,
|
||||
'pager' => $pager,
|
||||
'sort' => $this->sort,
|
||||
'context' => $context,
|
||||
'filters' => [
|
||||
'show' => null !== $configuration->getForm('filter'),
|
||||
'isEmpty' => empty($this->filters),
|
||||
|
@ -49,13 +50,13 @@ abstract class CrudController extends AdminController
|
|||
]);
|
||||
}
|
||||
|
||||
protected function doNew(EntityInterface $entity, EntityManager $entityManager, Request $request, callable $beforeCreate = null): Response
|
||||
protected function doNew(EntityInterface $entity, EntityManager $entityManager, Request $request, callable $beforeCreate = null, string $context = 'new'): Response
|
||||
{
|
||||
$configuration = $this->getConfiguration();
|
||||
|
||||
$this->prepareEntity($entity);
|
||||
|
||||
$form = $this->createForm($configuration->getForm('new'), $entity, $configuration->getFormOptions('new'));
|
||||
$form = $this->createForm($configuration->getForm('new'), $entity, $configuration->getFormOptions($context));
|
||||
|
||||
if ($request->isMethod('POST')) {
|
||||
$form->handleRequest($request);
|
||||
|
@ -76,30 +77,32 @@ abstract class CrudController extends AdminController
|
|||
$this->addFlash('warning', 'The form is not valid.');
|
||||
}
|
||||
|
||||
return $this->render($configuration->getView('new'), [
|
||||
return $this->render($configuration->getView($context), [
|
||||
'form' => $form->createView(),
|
||||
'configuration' => $configuration,
|
||||
'context' => $context,
|
||||
'entity' => $entity,
|
||||
]);
|
||||
}
|
||||
|
||||
protected function doShow(EntityInterface $entity): Response
|
||||
protected function doShow(EntityInterface $entity, string $context = 'show'): Response
|
||||
{
|
||||
$configuration = $this->getConfiguration();
|
||||
|
||||
return $this->render($configuration->getView('show'), [
|
||||
return $this->render($configuration->getView($context), [
|
||||
'entity' => $entity,
|
||||
'context' => $context,
|
||||
'configuration' => $configuration,
|
||||
]);
|
||||
}
|
||||
|
||||
protected function doEdit(EntityInterface $entity, EntityManager $entityManager, Request $request, callable $beforeUpdate = null): Response
|
||||
protected function doEdit(EntityInterface $entity, EntityManager $entityManager, Request $request, callable $beforeUpdate = null, string $context = 'edit'): Response
|
||||
{
|
||||
$configuration = $this->getConfiguration();
|
||||
|
||||
$this->prepareEntity($entity);
|
||||
|
||||
$form = $this->createForm($configuration->getForm('edit'), $entity, $configuration->getFormOptions('edit'));
|
||||
$form = $this->createForm($configuration->getForm('edit'), $entity, $configuration->getFormOptions($context));
|
||||
|
||||
if ($request->isMethod('POST')) {
|
||||
$form->handleRequest($request);
|
||||
|
@ -112,16 +115,17 @@ abstract class CrudController extends AdminController
|
|||
$entityManager->update($entity);
|
||||
$this->addFlash('success', 'The data has been saved.');
|
||||
|
||||
return $this->redirectToRoute($configuration->getPageRoute('edit'), array_merge(
|
||||
return $this->redirectToRoute($configuration->getPageRoute($context), array_merge(
|
||||
['entity' => $entity->getId()],
|
||||
$configuration->getPageRouteParams('edit')
|
||||
$configuration->getPageRouteParams($context)
|
||||
));
|
||||
}
|
||||
$this->addFlash('warning', 'The form is not valid.');
|
||||
}
|
||||
|
||||
return $this->render($configuration->getView('edit'), [
|
||||
return $this->render($configuration->getView($context), [
|
||||
'form' => $form->createView(),
|
||||
'context' => $context,
|
||||
'configuration' => $configuration,
|
||||
'entity' => $entity,
|
||||
]);
|
||||
|
@ -135,6 +139,7 @@ abstract class CrudController extends AdminController
|
|||
|
||||
$builder = $this->createFormBuilder($entity);
|
||||
$callback = $configuration->getFields($context)[$label]['options']['inline_form'] ?? null;
|
||||
$validationCallback = $configuration->getFields($context)[$label]['options']['inline_form_validation'] ?? null;
|
||||
|
||||
if (null === $callback) {
|
||||
throw $this->createNotFoundException();
|
||||
|
@ -142,27 +147,67 @@ abstract class CrudController extends AdminController
|
|||
|
||||
call_user_func_array($callback, [$builder, $entity]);
|
||||
|
||||
$form = $builder->getForm();
|
||||
$redirectTo = $request->query->get('redirectTo');
|
||||
|
||||
$form = $builder->getForm();
|
||||
$session = $request->getSession();
|
||||
|
||||
$lastRequestId = sprintf(
|
||||
'inline_request_%s_%s_%s_%s',
|
||||
get_class($entity),
|
||||
$entity->getId(),
|
||||
$context,
|
||||
$label
|
||||
);
|
||||
|
||||
$lastRequest = $session->get($lastRequestId);
|
||||
|
||||
if (null !== $lastRequest && !$request->isMethod('POST')) {
|
||||
$fakeRequest = Request::create(
|
||||
uri: $request->getUri(),
|
||||
method: 'POST',
|
||||
parameters: [$form->getName() => $lastRequest]
|
||||
);
|
||||
|
||||
$form->handleRequest($fakeRequest);
|
||||
|
||||
if (null !== $validationCallback) {
|
||||
call_user_func_array($validationCallback, [$entity, $form, $request]);
|
||||
}
|
||||
|
||||
$session->remove($lastRequestId);
|
||||
}
|
||||
|
||||
if ($request->isMethod('POST')) {
|
||||
$form->handleRequest($request);
|
||||
|
||||
if (null !== $validationCallback) {
|
||||
call_user_func_array($validationCallback, [$entity, $form, $request]);
|
||||
}
|
||||
|
||||
if ($form->isValid()) {
|
||||
if (null !== $beforeUpdate) {
|
||||
call_user_func_array($beforeUpdate, [$entity, $form, $request]);
|
||||
}
|
||||
|
||||
$session->remove($lastRequestId);
|
||||
$entityManager->update($entity);
|
||||
$this->addFlash('success', 'The data has been saved.');
|
||||
} else {
|
||||
$this->addFlash('warning', 'The form is not valid.');
|
||||
|
||||
return $this->redirect($redirectTo);
|
||||
}
|
||||
|
||||
return $this->redirect($redirectTo);
|
||||
$session->set($lastRequestId, $request->request->get('form'));
|
||||
$this->addFlash('warning', 'The form is not valid.');
|
||||
|
||||
return $this->redirect(sprintf(
|
||||
'%s?data-modal=%s',
|
||||
$redirectTo,
|
||||
urlencode($request->getUri())
|
||||
));
|
||||
}
|
||||
|
||||
return $this->render('@Core/admin/crud/inline_edit.html.twig', [
|
||||
return $this->render($configuration->getView('inline_edit'), [
|
||||
'form' => $form->createView(),
|
||||
'configuration' => $configuration,
|
||||
'entity' => $entity,
|
||||
|
@ -239,16 +284,39 @@ abstract class CrudController extends AdminController
|
|||
|
||||
$query->useFilters($this->filters);
|
||||
|
||||
if ('selection' === $target) {
|
||||
$isSelection = true;
|
||||
$pager = $query->paginate($page, $configuration->getMaxPerPage($context));
|
||||
} else {
|
||||
$isSelection = false;
|
||||
$pager = $query->find();
|
||||
$useSelection = 'selection' === $target;
|
||||
|
||||
if ($batchAction['isGlobal']) {
|
||||
$selection = null;
|
||||
|
||||
if ($useSelection) {
|
||||
$queryClone = clone $query;
|
||||
$pager = $queryClone->paginate($page, $configuration->getMaxPerPage($context));
|
||||
$selection = [];
|
||||
|
||||
foreach ($pager as $key => $entity) {
|
||||
if (isset($items[$key + 1])) {
|
||||
$selection[] = $entity;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$result = $callback($query, $entityManager, $selection);
|
||||
|
||||
if ($result instanceof Response) {
|
||||
return $result;
|
||||
}
|
||||
|
||||
return $this->redirect($request->query->get('redirectTo'));
|
||||
}
|
||||
|
||||
$pager = $useSelection
|
||||
? $query->paginate($page, $configuration->getMaxPerPage($context))
|
||||
: $query->find()
|
||||
;
|
||||
|
||||
foreach ($pager as $key => $entity) {
|
||||
if (($isSelection && isset($items[$key + 1])) || !$isSelection) {
|
||||
if (($useSelection && isset($items[$key + 1])) || !$useSelection) {
|
||||
$callback($entity, $entityManager);
|
||||
}
|
||||
}
|
||||
|
@ -258,7 +326,7 @@ abstract class CrudController extends AdminController
|
|||
return $this->json([]);
|
||||
}
|
||||
|
||||
protected function doDelete(EntityInterface $entity, EntityManager $entityManager, Request $request, callable $beforeDelete = null): Response
|
||||
protected function doDelete(EntityInterface $entity, EntityManager $entityManager, Request $request, callable $beforeDelete = null, string $route = 'index'): Response
|
||||
{
|
||||
$configuration = $this->getConfiguration();
|
||||
|
||||
|
@ -272,10 +340,10 @@ abstract class CrudController extends AdminController
|
|||
$this->addFlash('success', 'The data has been removed.');
|
||||
}
|
||||
|
||||
return $this->redirectToRoute($configuration->getPageRoute('index'));
|
||||
return $this->redirectToRoute($configuration->getPageRoute($route));
|
||||
}
|
||||
|
||||
protected function doFilter(Session $session): Response
|
||||
protected function doFilter(Session $session, string $context = 'filter'): Response
|
||||
{
|
||||
$configuration = $this->getConfiguration();
|
||||
$type = $configuration->getForm('filter');
|
||||
|
@ -284,11 +352,12 @@ abstract class CrudController extends AdminController
|
|||
throw $this->createNotFoundException();
|
||||
}
|
||||
|
||||
$form = $this->createForm($type);
|
||||
$form = $this->createForm($type, null, $configuration->getFormOptions('filter'));
|
||||
$form->submit($session->get($form->getName(), []));
|
||||
|
||||
return $this->render($configuration->getView('filter'), [
|
||||
return $this->render($configuration->getView($context), [
|
||||
'form' => $form->createView(),
|
||||
'context' => $context,
|
||||
'configuration' => $configuration,
|
||||
]);
|
||||
}
|
||||
|
@ -302,7 +371,7 @@ abstract class CrudController extends AdminController
|
|||
return;
|
||||
}
|
||||
|
||||
$form = $this->createForm($type);
|
||||
$form = $this->createForm($type, null, $configuration->getFormOptions('filter'));
|
||||
|
||||
if ($request->query->has($form->getName())) {
|
||||
$filters = $request->query->get($form->getName());
|
||||
|
@ -349,9 +418,27 @@ abstract class CrudController extends AdminController
|
|||
}
|
||||
|
||||
$defaultSort = $configuration->getDefaultSort($context);
|
||||
$session = $request->getSession();
|
||||
|
||||
$name = $request->query->get('_sort', $defaultSort['label'] ?? null);
|
||||
$direction = strtolower($request->query->get('_sort_direction', $defaultSort['direction'] ?? 'asc'));
|
||||
$sessionId = sprintf('%s_%s_sort', $context, get_called_class());
|
||||
$sessionSortName = sprintf('%s_label', $sessionId);
|
||||
$sessionSortDirection = sprintf('%s_direction', $sessionId);
|
||||
|
||||
$name = $request->query->get('_sort', $session->get($sessionSortName)) ?? $defaultSort['label'] ?? null;
|
||||
|
||||
$direction = strtolower(
|
||||
$request->query->get(
|
||||
'_sort_direction',
|
||||
$session->get($sessionSortDirection)
|
||||
) ?? $defaultSort['direction'] ?? 'asc'
|
||||
);
|
||||
|
||||
$session->set($sessionSortName, $name);
|
||||
$session->set($sessionSortDirection, $direction);
|
||||
|
||||
if (empty($name)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!in_array($direction, ['asc', 'desc'])) {
|
||||
$direction = 'asc';
|
||||
|
|
|
@ -3,8 +3,6 @@
|
|||
namespace App\Core\Controller\Dashboard;
|
||||
|
||||
use App\Core\Controller\Admin\AdminController;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\Routing\Annotation\Route;
|
||||
|
||||
class DashboardAdminController extends AdminController
|
||||
{
|
||||
|
|
|
@ -102,11 +102,11 @@ class RedirectAdminController extends CrudController
|
|||
'attr' => ['class' => 'col-6'],
|
||||
])
|
||||
->setField('index', 'Enabled', Field\ButtonField::class, [
|
||||
'property_builder' => function(EntityInterface $entity) {
|
||||
'property_builder' => function (EntityInterface $entity) {
|
||||
return $entity->getIsEnabled() ? 'Yes' : 'No';
|
||||
},
|
||||
'attr' => ['class' => 'col-1'],
|
||||
'button_attr_builder' => function(EntityInterface $entity) {
|
||||
'button_attr_builder' => function (EntityInterface $entity) {
|
||||
return ['class' => 'btn btn-sm btn-'.($entity->getIsEnabled() ? 'success' : 'primary')];
|
||||
},
|
||||
])
|
||||
|
|
|
@ -31,11 +31,28 @@ class NavigationSettingAdminController extends AdminController
|
|||
$eventDispatcher->dispatch($event, NavigationSettingEvent::FORM_INIT_EVENT);
|
||||
|
||||
$form = $builder->getForm();
|
||||
$redirectTo = $request->query->get('redirectTo');
|
||||
$session = $request->getSession();
|
||||
$lastRequestId = sprintf('setting_request_%s_%s', get_class($entity), $entity->getId());
|
||||
$lastRequest = $session->get($lastRequestId);
|
||||
|
||||
if (null !== $lastRequest && !$request->isMethod('POST')) {
|
||||
$fakeRequest = Request::create(
|
||||
uri: $request->getUri(),
|
||||
method: 'POST',
|
||||
parameters: [$form->getName() => $lastRequest]
|
||||
);
|
||||
|
||||
$form->handleRequest($fakeRequest);
|
||||
$session->remove($lastRequestId);
|
||||
}
|
||||
|
||||
if ($request->isMethod('POST')) {
|
||||
$form->handleRequest($request);
|
||||
|
||||
if ($form->isValid()) {
|
||||
$entityManager->update($entity);
|
||||
$session->remove($lastRequestId);
|
||||
$entityManager->update($entity);
|
||||
$this->addFlash('success', 'The data has been saved.');
|
||||
|
||||
|
@ -44,13 +61,21 @@ class NavigationSettingAdminController extends AdminController
|
|||
]);
|
||||
}
|
||||
|
||||
$session->set($lastRequestId, $request->request->get('form'));
|
||||
$this->addFlash('warning', 'The form is not valid.');
|
||||
|
||||
return $this->redirect(sprintf(
|
||||
'%s?data-modal=%s',
|
||||
$redirectTo,
|
||||
urlencode($request->getUri())
|
||||
));
|
||||
}
|
||||
|
||||
return $this->render('@Core/setting/navigation_setting_admin/edit.html.twig', [
|
||||
'form' => $form->createView(),
|
||||
'entity' => $entity,
|
||||
'options' => $event->getData()['options'],
|
||||
'redirectTo' => $redirectTo,
|
||||
]);
|
||||
}
|
||||
|
||||
|
|
|
@ -12,14 +12,10 @@ use Symfony\Component\HttpFoundation\Request;
|
|||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\Routing\Annotation\Route;
|
||||
|
||||
/**
|
||||
* @Route("/admin/setting")
|
||||
*/
|
||||
#[Route(path: '/admin/setting')]
|
||||
class SettingAdminController extends AdminController
|
||||
{
|
||||
/**
|
||||
* @Route("/{page}", name="admin_setting_index", requirements={"page": "\d+"})
|
||||
*/
|
||||
#[Route(path: '/{page}', name: 'admin_setting_index', requirements: ['page' => '\d+'])]
|
||||
public function index(
|
||||
RepositoryQuery $query,
|
||||
EventDispatcherInterface $eventDispatcher,
|
||||
|
@ -38,9 +34,7 @@ class SettingAdminController extends AdminController
|
|||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @Route("/edit/{entity}", name="admin_setting_edit")
|
||||
*/
|
||||
#[Route(path: '/edit/{entity}', name: 'admin_setting_edit')]
|
||||
public function edit(
|
||||
Entity $entity,
|
||||
EntityManager $entityManager,
|
||||
|
@ -57,30 +51,53 @@ class SettingAdminController extends AdminController
|
|||
$eventDispatcher->dispatch($event, SettingEvent::FORM_INIT_EVENT);
|
||||
|
||||
$form = $builder->getForm();
|
||||
$redirectTo = $request->query->get('redirectTo');
|
||||
$session = $request->getSession();
|
||||
$lastRequestId = sprintf('setting_request_%s_%s', get_class($entity), $entity->getId());
|
||||
$lastRequest = $session->get($lastRequestId);
|
||||
|
||||
if (null !== $lastRequest && !$request->isMethod('POST')) {
|
||||
$fakeRequest = Request::create(
|
||||
uri: $request->getUri(),
|
||||
method: 'POST',
|
||||
parameters: [$form->getName() => $lastRequest]
|
||||
);
|
||||
|
||||
$form->handleRequest($fakeRequest);
|
||||
$session->remove($lastRequestId);
|
||||
}
|
||||
|
||||
if ($request->isMethod('POST')) {
|
||||
$form->handleRequest($request);
|
||||
|
||||
if ($form->isValid()) {
|
||||
$entityManager->update($entity);
|
||||
$session->remove($lastRequestId);
|
||||
$entityManager->update($entity);
|
||||
$this->addFlash('success', 'The data has been saved.');
|
||||
|
||||
return $this->redirectToRoute('admin_setting_index');
|
||||
}
|
||||
|
||||
$session->set($lastRequestId, $request->request->get('form'));
|
||||
$this->addFlash('warning', 'The form is not valid.');
|
||||
|
||||
return $this->redirect(sprintf(
|
||||
'%s?data-modal=%s',
|
||||
$redirectTo,
|
||||
urlencode($request->getUri())
|
||||
));
|
||||
}
|
||||
|
||||
return $this->render('@Core/setting/setting_admin/edit.html.twig', [
|
||||
'form' => $form->createView(),
|
||||
'entity' => $entity,
|
||||
'options' => $event->getData()['options'],
|
||||
'redirectTo' => $redirectTo,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @Route("/delete/{entity}", name="admin_setting_delete", methods={"DELETE"})
|
||||
*/
|
||||
#[Route(path: '/delete/{entity}', name: 'admin_setting_delete', methods: ['DELETE', 'POST'])]
|
||||
public function delete(Entity $entity, EntityManager $entityManager, Request $request): Response
|
||||
{
|
||||
if ($this->isCsrfTokenValid('delete'.$entity->getId(), $request->request->get('_token'))) {
|
||||
|
|
|
@ -67,7 +67,7 @@ class NavigationAdminController extends CrudController
|
|||
}
|
||||
|
||||
#[Route(path: '/admin/site/navigation/sort/{page}', name: 'admin_site_navigation_sort', methods: ['POST'], requirements: ['page' => '\d+'])]
|
||||
public function sort(RepositoryQuery $query, EntityManager $entityManager, Request $request, Session $session, int $page = 1, ): Response
|
||||
public function sort(RepositoryQuery $query, EntityManager $entityManager, Request $request, Session $session, int $page = 1): Response
|
||||
{
|
||||
return $this->doSort($page, $query, $entityManager, $request, $session);
|
||||
}
|
||||
|
@ -104,9 +104,11 @@ class NavigationAdminController extends CrudController
|
|||
->setView('form', '@Core/site/navigation_admin/_form.html.twig')
|
||||
|
||||
->setIsSortableCollection('index', true)
|
||||
->setDoubleClick('index', true)
|
||||
|
||||
->setField('index', 'Label', Field\TextField::class, [
|
||||
'property' => 'label',
|
||||
'view' => '@Core/site/navigation_admin/field/label.html.twig',
|
||||
'attr' => ['class' => 'miw-200'],
|
||||
])
|
||||
->setField('index', 'Domain', Field\ButtonField::class, [
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
|
||||
namespace App\Core\Controller\Site;
|
||||
|
||||
use App\Core\Controller\Admin\AdminController;
|
||||
use App\Core\Entity\Site\Node;
|
||||
use App\Core\Entity\Site\Node as Entity;
|
||||
use App\Core\Entity\Site\Page\Page;
|
||||
|
@ -14,15 +13,15 @@ use App\Core\Form\Site\NodeType as EntityType;
|
|||
use App\Core\Manager\EntityManager;
|
||||
use App\Core\Repository\Site\NodeRepository;
|
||||
use App\Core\Site\ControllerLocator;
|
||||
use App\Core\Site\RoleLocator;
|
||||
use App\Core\Site\PageLocator;
|
||||
use App\Core\Site\RoleLocator;
|
||||
use App\Core\Sitemap\SitemapBuilder;
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
|
||||
use Symfony\Component\Form\FormError;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\Routing\Annotation\Route;
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||
|
||||
#[Route(path: '/admin/site/node')]
|
||||
class NodeAdminController extends AbstractController
|
||||
|
@ -145,7 +144,7 @@ class NodeAdminController extends AbstractController
|
|||
|
||||
$page = $entity->getPage();
|
||||
|
||||
if ($page !== null) {
|
||||
if (null !== $page) {
|
||||
$pageConfiguration = $pageLocator->getPages()[get_class($page)] ?? null;
|
||||
} else {
|
||||
$pageConfiguration = null;
|
||||
|
|
|
@ -5,19 +5,19 @@ namespace App\Core\Controller\Site;
|
|||
use App\Core\Controller\Admin\Crud\CrudController;
|
||||
use App\Core\Crud\CrudConfiguration;
|
||||
use App\Core\Crud\Field;
|
||||
use App\Core\Entity\EntityInterface;
|
||||
use App\Core\Entity\Site\Page\Page as Entity;
|
||||
use App\Core\Event\Page\PageEditEvent;
|
||||
use App\Core\Form\Site\Page\Filter\PageFilterType as FilterType;
|
||||
use App\Core\Form\Site\Page\PageType as Type;
|
||||
use App\Core\Manager\EntityManager;
|
||||
use App\Core\Repository\Site\Page\PageRepositoryQuery as RepositoryQuery;
|
||||
use App\Core\Site\PageLocator;
|
||||
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\HttpFoundation\Session\Session;
|
||||
use Symfony\Component\Routing\Annotation\Route;
|
||||
use App\Core\Event\Page\PageEditEvent;
|
||||
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
|
||||
use App\Core\Entity\EntityInterface;
|
||||
|
||||
class PageAdminController extends CrudController
|
||||
{
|
||||
|
@ -95,6 +95,8 @@ class PageAdminController extends CrudController
|
|||
->setAction('index', 'show', false)
|
||||
->setAction('edit', 'show', false)
|
||||
|
||||
->setDoubleClick('index', true)
|
||||
|
||||
->setField('index', 'Name', Field\TextField::class, [
|
||||
'property' => 'name',
|
||||
'sort' => ['name', '.name'],
|
||||
|
@ -112,7 +114,7 @@ class PageAdminController extends CrudController
|
|||
}],
|
||||
'attr' => ['class' => 'col-6'],
|
||||
])
|
||||
->setBatchAction('index', 'delete', 'Delete', function(EntityInterface $entity, EntityManager $manager) {
|
||||
->setBatchAction('index', 'delete', 'Delete', function (EntityInterface $entity, EntityManager $manager) {
|
||||
$manager->delete($entity);
|
||||
})
|
||||
;
|
||||
|
|
|
@ -8,55 +8,55 @@ use App\Core\Crud\Field;
|
|||
use App\Core\Event\Account\PasswordRequestEvent;
|
||||
use App\Core\Factory\UserFactory as Factory;
|
||||
use App\Core\Manager\EntityManager;
|
||||
use App\Core\Security\TokenGenerator;
|
||||
use App\Entity\User as Entity;
|
||||
use App\Form\UserType as Type;
|
||||
use App\Repository\UserRepositoryQuery as RepositoryQuery;
|
||||
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
|
||||
use Symfony\Component\Form\FormBuilderInterface;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\HttpFoundation\Session\Session;
|
||||
use Symfony\Component\Routing\Annotation\Route;
|
||||
use App\Core\Security\TokenGenerator;
|
||||
|
||||
class UserAdminController extends CrudController
|
||||
{
|
||||
#[Route(path: '/admin/user/{page}', name: 'admin_user_index', methods: ['GET'], requirements: ['page' => '\d+'])]
|
||||
protected ?CrudConfiguration $configuration = null;
|
||||
|
||||
public function index(RepositoryQuery $query, Request $request, Session $session, int $page = 1): Response
|
||||
{
|
||||
return $this->doIndex($page, $query, $request, $session);
|
||||
}
|
||||
|
||||
#[Route(path: '/admin/user/new', name: 'admin_user_new', methods: ['GET', 'POST'])]
|
||||
public function new(Factory $factory, EntityManager $entityManager, Request $request, TokenGenerator $tokenGenerator): Response
|
||||
{
|
||||
return $this->doNew($factory->create(null, $tokenGenerator->generateToken()), $entityManager, $request);
|
||||
}
|
||||
|
||||
#[Route(path: '/admin/user/show/{entity}', name: 'admin_user_show', methods: ['GET'])]
|
||||
public function show(Entity $entity): Response
|
||||
{
|
||||
return $this->doShow($entity);
|
||||
}
|
||||
|
||||
#[Route(path: '/admin/user/filter', name: 'admin_user_filter', methods: ['GET'])]
|
||||
public function filter(Session $session): Response
|
||||
{
|
||||
return $this->doFilter($session);
|
||||
}
|
||||
|
||||
#[Route(path: '/admin/user/edit/{entity}', name: 'admin_user_edit', methods: ['GET', 'POST'])]
|
||||
public function edit(Entity $entity, EntityManager $entityManager, Request $request): Response
|
||||
{
|
||||
return $this->doEdit($entity, $entityManager, $request);
|
||||
}
|
||||
|
||||
#[Route(path: '/admin/user/delete/{entity}', name: 'admin_user_delete', methods: ['DELETE', 'POST'])]
|
||||
public function inlineEdit(string $context, string $label, Entity $entity, EntityManager $entityManager, Request $request): Response
|
||||
{
|
||||
return $this->doInlineEdit($context, $label, $entity, $entityManager, $request);
|
||||
}
|
||||
|
||||
public function delete(Entity $entity, EntityManager $entityManager, Request $request): Response
|
||||
{
|
||||
return $this->doDelete($entity, $entityManager, $request);
|
||||
}
|
||||
|
||||
#[Route(path: '/admin/user/resetting_request/{entity}', name: 'admin_user_resetting_request', methods: ['POST'])]
|
||||
public function requestResetting(Entity $entity, EventDispatcherInterface $eventDispatcher, Request $request): Response
|
||||
{
|
||||
if ($this->isCsrfTokenValid('resetting_request'.$entity->getId(), $request->request->get('_token'))) {
|
||||
|
@ -81,6 +81,7 @@ class UserAdminController extends CrudController
|
|||
->setPageRoute('index', 'admin_user_index')
|
||||
->setPageRoute('new', 'admin_user_new')
|
||||
->setPageRoute('edit', 'admin_user_edit')
|
||||
->setPageRoute('inline_edit', 'admin_user_inline_edit')
|
||||
->setPageRoute('show', 'admin_user_show')
|
||||
->setPageRoute('delete', 'admin_user_delete')
|
||||
->setPageRoute('filter', 'admin_user_filter')
|
||||
|
@ -96,6 +97,7 @@ class UserAdminController extends CrudController
|
|||
->setView('edit', '@Core/user/user_admin/edit.html.twig')
|
||||
|
||||
->setDefaultSort('index', 'username')
|
||||
->setDoubleClick('index', true)
|
||||
|
||||
->setField('index', 'E-mail', Field\TextField::class, [
|
||||
'property' => 'email',
|
||||
|
@ -106,6 +108,9 @@ class UserAdminController extends CrudController
|
|||
'property' => 'displayName',
|
||||
'sort' => ['displayName', '.displayName'],
|
||||
'attr' => ['class' => 'miw-200'],
|
||||
'inline_form' => function (FormBuilderInterface $builder) {
|
||||
$builder->add('displayName', null);
|
||||
},
|
||||
])
|
||||
;
|
||||
}
|
||||
|
|
|
@ -40,7 +40,7 @@ class CrudConfiguration
|
|||
return self::$self;
|
||||
}
|
||||
|
||||
/* -- */
|
||||
// --
|
||||
|
||||
public function setPageTitle(string $page, string $title): self
|
||||
{
|
||||
|
@ -54,7 +54,7 @@ class CrudConfiguration
|
|||
return $this->pageTitles[$page] ?? $default;
|
||||
}
|
||||
|
||||
/* -- */
|
||||
// --
|
||||
|
||||
public function setPageRoute(string $page, string $route): self
|
||||
{
|
||||
|
@ -80,9 +80,9 @@ class CrudConfiguration
|
|||
return $this->pageRouteParams[$page] ?? [];
|
||||
}
|
||||
|
||||
/* -- */
|
||||
// --
|
||||
|
||||
public function setForm(string $context, string $form, array $options = []): self
|
||||
public function setForm(string $context, string $form): self
|
||||
{
|
||||
$this->forms[$context] = $form;
|
||||
|
||||
|
@ -106,7 +106,7 @@ class CrudConfiguration
|
|||
return $this->formOptions[$context] ?? [];
|
||||
}
|
||||
|
||||
/* -- */
|
||||
// --
|
||||
|
||||
public function setAction(string $page, string $action, bool|callable $enabled): self
|
||||
{
|
||||
|
@ -135,8 +135,24 @@ class CrudConfiguration
|
|||
);
|
||||
}
|
||||
|
||||
public function setBatchAction(string $page, string $action, string $label, callable $callback): self
|
||||
{
|
||||
public function setGlobalBatchAction(
|
||||
string $page,
|
||||
string $action,
|
||||
string $label,
|
||||
callable $callback
|
||||
): self {
|
||||
$this->setBatchAction($page, $action, $label, $callback);
|
||||
$this->batchActions[$page][$action]['isGlobal'] = true;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setBatchAction(
|
||||
string $page,
|
||||
string $action,
|
||||
string $label,
|
||||
callable $callback
|
||||
): self {
|
||||
if (!isset($this->batchActions[$page])) {
|
||||
$this->batchActions[$page] = [];
|
||||
}
|
||||
|
@ -144,6 +160,7 @@ class CrudConfiguration
|
|||
$this->batchActions[$page][$action] = [
|
||||
'label' => $label,
|
||||
'callback' => $callback,
|
||||
'isGlobal' => false,
|
||||
];
|
||||
|
||||
return $this;
|
||||
|
@ -164,7 +181,7 @@ class CrudConfiguration
|
|||
return !empty($this->batchActions[$page]);
|
||||
}
|
||||
|
||||
/* -- */
|
||||
// --
|
||||
|
||||
public function setActionTitle(string $page, string $action, string $title): self
|
||||
{
|
||||
|
@ -182,7 +199,7 @@ class CrudConfiguration
|
|||
return $this->actionTitles[$page][$action] ?? $default;
|
||||
}
|
||||
|
||||
/* -- */
|
||||
// --
|
||||
|
||||
public function setView(string $context, string $view): self
|
||||
{
|
||||
|
@ -230,7 +247,7 @@ class CrudConfiguration
|
|||
return $this->viewDatas[$context][$name] ?? $defaultValue;
|
||||
}
|
||||
|
||||
/* -- */
|
||||
// --
|
||||
|
||||
public function setField(string $context, string $label, string $field, array $options): self
|
||||
{
|
||||
|
@ -251,7 +268,14 @@ class CrudConfiguration
|
|||
return $this->fields[$context] ?? [];
|
||||
}
|
||||
|
||||
/* -- */
|
||||
public function setFields(string $context, array $fields): self
|
||||
{
|
||||
$this->fields[$context] = $fields;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
// --
|
||||
|
||||
public function setMaxPerPage(string $page, int $max): self
|
||||
{
|
||||
|
@ -265,7 +289,7 @@ class CrudConfiguration
|
|||
return $this->maxPerPage[$page] ?? $default;
|
||||
}
|
||||
|
||||
/* -- */
|
||||
// --
|
||||
|
||||
public function setDoubleClick(string $page, bool $enabled): self
|
||||
{
|
||||
|
@ -279,7 +303,7 @@ class CrudConfiguration
|
|||
return $this->doubleClick[$page] ?? false;
|
||||
}
|
||||
|
||||
/* -- */
|
||||
// --
|
||||
|
||||
public function setI18n(array $locales, string $defaultLocale): self
|
||||
{
|
||||
|
@ -304,7 +328,7 @@ class CrudConfiguration
|
|||
return !empty($this->locales);
|
||||
}
|
||||
|
||||
/* -- */
|
||||
// --
|
||||
|
||||
public function setDefaultSort(string $context, string $label, string $direction = 'asc'): self
|
||||
{
|
||||
|
|
32
src/core/Crud/Field/BooleanField.php
Normal file
32
src/core/Crud/Field/BooleanField.php
Normal file
|
@ -0,0 +1,32 @@
|
|||
<?php
|
||||
|
||||
namespace App\Core\Crud\Field;
|
||||
|
||||
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||
|
||||
/**
|
||||
* class BooleanField.
|
||||
*
|
||||
* @author Simon Vieille <simon@deblan.fr>
|
||||
*/
|
||||
class BooleanField extends Field
|
||||
{
|
||||
public function configureOptions(OptionsResolver $resolver): OptionsResolver
|
||||
{
|
||||
parent::configureOptions($resolver);
|
||||
|
||||
$resolver->setDefaults([
|
||||
'view' => '@Core/admin/crud/field/boolean.html.twig',
|
||||
'display' => 'toggle',
|
||||
'checkbox_class_when_true' => 'fa-check-square',
|
||||
'checkbox_class_when_false' => 'fa-square',
|
||||
'toggle_class_when_true' => 'bg-success',
|
||||
'toggle_class_when_false' => 'bg-secondary',
|
||||
'default_value' => false,
|
||||
]);
|
||||
|
||||
$resolver->setAllowedTypes('display', 'string');
|
||||
|
||||
return $resolver;
|
||||
}
|
||||
}
|
|
@ -28,6 +28,7 @@ abstract class Field
|
|||
$resolver->setDefaults([
|
||||
'property' => null,
|
||||
'property_builder' => null,
|
||||
'default_value' => null,
|
||||
'view' => null,
|
||||
'action' => null,
|
||||
'raw' => false,
|
||||
|
@ -36,6 +37,7 @@ abstract class Field
|
|||
'href_attr' => [],
|
||||
'attr' => [],
|
||||
'inline_form' => null,
|
||||
'inline_form_validation' => null,
|
||||
]);
|
||||
|
||||
$resolver->setRequired('view');
|
||||
|
@ -45,11 +47,12 @@ abstract class Field
|
|||
$resolver->setAllowedTypes('attr', 'array');
|
||||
$resolver->setAllowedTypes('href', ['null', 'string', 'callable']);
|
||||
$resolver->setAllowedTypes('inline_form', ['null', 'callable']);
|
||||
$resolver->setAllowedTypes('href_attr', 'array', 'callable');
|
||||
$resolver->setAllowedTypes('inline_form_validation', ['null', 'callable']);
|
||||
$resolver->setAllowedTypes('href_attr', ['array', 'callable']);
|
||||
$resolver->setAllowedTypes('raw', 'boolean');
|
||||
$resolver->setAllowedTypes('property_builder', ['null', 'callable']);
|
||||
$resolver->setAllowedValues('sort', function($value) {
|
||||
if ($value === null) {
|
||||
$resolver->setAllowedValues('sort', function ($value) {
|
||||
if (null === $value) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -46,101 +46,100 @@ class Configuration implements ConfigurationInterface
|
|||
|
||||
$treeBuilder->getRootNode()
|
||||
->children()
|
||||
->arrayNode('site')
|
||||
->children()
|
||||
->scalarNode('name')
|
||||
->defaultValue('Murph')
|
||||
->isRequired()
|
||||
->cannotBeEmpty()
|
||||
->end()
|
||||
->scalarNode('logo')
|
||||
->defaultValue('build/images/core/logo.svg')
|
||||
->isRequired()
|
||||
->cannotBeEmpty()
|
||||
->end()
|
||||
->arrayNode('controllers')
|
||||
->prototype('array')
|
||||
->children()
|
||||
->scalarNode('name')
|
||||
->cannotBeEmpty()
|
||||
->end()
|
||||
->scalarNode('action')
|
||||
->cannotBeEmpty()
|
||||
->end()
|
||||
->end()
|
||||
->end()
|
||||
->end()
|
||||
->arrayNode('security')
|
||||
->children()
|
||||
->arrayNode('roles')
|
||||
->prototype('array')
|
||||
->children()
|
||||
->scalarNode('name')
|
||||
->cannotBeEmpty()
|
||||
->end()
|
||||
->scalarNode('role')
|
||||
->cannotBeEmpty()
|
||||
->end()
|
||||
->end()
|
||||
->end()
|
||||
->end()
|
||||
->end()
|
||||
->end()
|
||||
->arrayNode('pages')
|
||||
->prototype('array')
|
||||
->children()
|
||||
->scalarNode('name')
|
||||
->isRequired()
|
||||
->cannotBeEmpty()
|
||||
->end()
|
||||
->arrayNode('templates')
|
||||
->prototype('array')
|
||||
->children()
|
||||
->scalarNode('name')
|
||||
->cannotBeEmpty()
|
||||
->end()
|
||||
->scalarNode('file')
|
||||
->cannotBeEmpty()
|
||||
->end()
|
||||
->end()
|
||||
->end()
|
||||
->end()
|
||||
->end()
|
||||
->end()
|
||||
->end()
|
||||
->end()
|
||||
->end()
|
||||
->arrayNode('editor_js')
|
||||
->children()
|
||||
->arrayNode('blocks')
|
||||
->scalarPrototype()
|
||||
->end()
|
||||
->end()
|
||||
->end()
|
||||
->end()
|
||||
->arrayNode('file_manager')
|
||||
->children()
|
||||
->arrayNode('mimes')
|
||||
->scalarPrototype()
|
||||
->end()
|
||||
->defaultValue($defaultMimetypes)
|
||||
->end()
|
||||
->scalarNode('path')
|
||||
->defaultValue('%kernel.project_dir%/public/uploads')
|
||||
->cannotBeEmpty()
|
||||
->end()
|
||||
->scalarNode('path_uri')
|
||||
->defaultValue('/uploads')
|
||||
->cannotBeEmpty()
|
||||
->end()
|
||||
->arrayNode('path_locked')
|
||||
->scalarPrototype()
|
||||
->end()
|
||||
->defaultValue($defaultLocked)
|
||||
->end()
|
||||
->end()
|
||||
->end()
|
||||
->end();
|
||||
->arrayNode('site')
|
||||
->children()
|
||||
->scalarNode('name')
|
||||
->defaultValue('Murph')
|
||||
->isRequired()
|
||||
->end()
|
||||
->scalarNode('logo')
|
||||
->defaultValue('build/images/core/logo.svg')
|
||||
->isRequired()
|
||||
->end()
|
||||
->arrayNode('controllers')
|
||||
->prototype('array')
|
||||
->children()
|
||||
->scalarNode('name')
|
||||
->cannotBeEmpty()
|
||||
->end()
|
||||
->scalarNode('action')
|
||||
->cannotBeEmpty()
|
||||
->end()
|
||||
->end()
|
||||
->end()
|
||||
->end()
|
||||
->arrayNode('security')
|
||||
->children()
|
||||
->arrayNode('roles')
|
||||
->prototype('array')
|
||||
->children()
|
||||
->scalarNode('name')
|
||||
->cannotBeEmpty()
|
||||
->end()
|
||||
->scalarNode('role')
|
||||
->cannotBeEmpty()
|
||||
->end()
|
||||
->end()
|
||||
->end()
|
||||
->end()
|
||||
->end()
|
||||
->end()
|
||||
->arrayNode('pages')
|
||||
->prototype('array')
|
||||
->children()
|
||||
->scalarNode('name')
|
||||
->isRequired()
|
||||
->cannotBeEmpty()
|
||||
->end()
|
||||
->arrayNode('templates')
|
||||
->prototype('array')
|
||||
->children()
|
||||
->scalarNode('name')
|
||||
->cannotBeEmpty()
|
||||
->end()
|
||||
->scalarNode('file')
|
||||
->cannotBeEmpty()
|
||||
->end()
|
||||
->end()
|
||||
->end()
|
||||
->end()
|
||||
->end()
|
||||
->end()
|
||||
->end()
|
||||
->end()
|
||||
->end()
|
||||
->arrayNode('editor_js')
|
||||
->children()
|
||||
->arrayNode('blocks')
|
||||
->scalarPrototype()
|
||||
->end()
|
||||
->end()
|
||||
->end()
|
||||
->end()
|
||||
->arrayNode('file_manager')
|
||||
->children()
|
||||
->arrayNode('mimes')
|
||||
->scalarPrototype()
|
||||
->end()
|
||||
->defaultValue($defaultMimetypes)
|
||||
->end()
|
||||
->scalarNode('path')
|
||||
->defaultValue('%kernel.project_dir%/public/uploads')
|
||||
->cannotBeEmpty()
|
||||
->end()
|
||||
->scalarNode('path_uri')
|
||||
->defaultValue('/uploads')
|
||||
->cannotBeEmpty()
|
||||
->end()
|
||||
->arrayNode('path_locked')
|
||||
->scalarPrototype()
|
||||
->end()
|
||||
->defaultValue($defaultLocked)
|
||||
->end()
|
||||
->end()
|
||||
->end()
|
||||
->end()
|
||||
;
|
||||
|
||||
return $treeBuilder;
|
||||
}
|
||||
|
|
|
@ -2,10 +2,9 @@
|
|||
|
||||
namespace App\Core\Entity\Analytic;
|
||||
|
||||
use App\Core\Entity\Site\Node;
|
||||
use App\Repository\Entity\Analytic\NodeViewRepository;
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
use App\Core\Entity\EntityInterface;
|
||||
use App\Core\Entity\Site\Node;
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
|
||||
#[ORM\Table(name: 'analytic_referer')]
|
||||
#[ORM\Entity(repositoryClass: ViewRepository::class)]
|
||||
|
|
|
@ -2,10 +2,9 @@
|
|||
|
||||
namespace App\Core\Entity\Analytic;
|
||||
|
||||
use App\Core\Entity\Site\Node;
|
||||
use App\Repository\Entity\Analytic\NodeViewRepository;
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
use App\Core\Entity\EntityInterface;
|
||||
use App\Core\Entity\Site\Node;
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
|
||||
#[ORM\Table(name: 'analytic_view')]
|
||||
#[ORM\Entity(repositoryClass: ViewRepository::class)]
|
||||
|
|
|
@ -42,6 +42,9 @@ class Navigation implements EntityInterface
|
|||
#[ORM\Column(type: 'string', length: 10)]
|
||||
protected $locale = 'en';
|
||||
|
||||
#[ORM\Column(type: 'string', length: 7, nullable: true)]
|
||||
protected $color;
|
||||
|
||||
#[ORM\Column(type: 'integer', nullable: true)]
|
||||
protected $sortOrder;
|
||||
|
||||
|
@ -64,7 +67,7 @@ class Navigation implements EntityInterface
|
|||
return $this->label;
|
||||
}
|
||||
|
||||
public function setLabel(string $label): self
|
||||
public function setLabel(?string $label): self
|
||||
{
|
||||
$this->label = $label;
|
||||
|
||||
|
@ -237,4 +240,16 @@ class Navigation implements EntityInterface
|
|||
|
||||
return false;
|
||||
}
|
||||
|
||||
public function setColor(string $color): self
|
||||
{
|
||||
$this->color = $color;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getColor(): ?string
|
||||
{
|
||||
return $this->color;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,13 +5,12 @@ namespace App\Core\Entity\Site\Page;
|
|||
use App\Core\Doctrine\Timestampable;
|
||||
use App\Core\Entity\EntityInterface;
|
||||
use App\Core\Entity\Site\Node;
|
||||
use App\Core\File\FileAttribute;
|
||||
use App\Core\Repository\Site\Page\PageRepository;
|
||||
use Doctrine\Common\Collections\ArrayCollection;
|
||||
use Doctrine\Common\Collections\Collection;
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
use Symfony\Component\Form\FormBuilderInterface;
|
||||
use Symfony\Component\HttpFoundation\File\File;
|
||||
use App\Core\File\FileAttribute;
|
||||
|
||||
#[ORM\Entity(repositoryClass: PageRepository::class)]
|
||||
#[ORM\DiscriminatorColumn(name: 'class_key', type: 'string')]
|
||||
|
@ -89,7 +88,7 @@ class Page implements EntityInterface
|
|||
}
|
||||
|
||||
/**
|
||||
* @return Collection|Block[]
|
||||
* @return Block[]|Collection
|
||||
*/
|
||||
public function getBlocks(): Collection
|
||||
{
|
||||
|
|
|
@ -15,11 +15,8 @@ class AbTestEvent extends Event
|
|||
public const INIT_EVENT = 'ab_test.init';
|
||||
public const RUN_EVENT = 'ab_test.run';
|
||||
|
||||
protected AbTest $test;
|
||||
|
||||
public function __construct(AbTest $test)
|
||||
public function __construct(protected AbTest $test)
|
||||
{
|
||||
$this->test = $test;
|
||||
}
|
||||
|
||||
public function getTest(): AbTest
|
||||
|
|
|
@ -12,13 +12,10 @@ use Symfony\Contracts\EventDispatcher\Event;
|
|||
*/
|
||||
class PasswordRequestEvent extends Event
|
||||
{
|
||||
const EVENT = 'account_event.password_request';
|
||||
public const EVENT = 'account_event.password_request';
|
||||
|
||||
protected User $user;
|
||||
|
||||
public function __construct(User $user)
|
||||
public function __construct(protected User $user)
|
||||
{
|
||||
$this->user = $user;
|
||||
}
|
||||
|
||||
public function getUser(): User
|
||||
|
|
|
@ -12,18 +12,15 @@ 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 PRE_UPDATE_EVENT = 'entity_manager_event.pre_update';
|
||||
const PRE_DELETE_EVENT = 'entity_manager_event.pre_delete';
|
||||
public const CREATE_EVENT = 'entity_manager_event.create';
|
||||
public const UPDATE_EVENT = 'entity_manager_event.update';
|
||||
public const DELETE_EVENT = 'entity_manager_event.delete';
|
||||
public const PRE_CREATE_EVENT = 'entity_manager_event.pre_create';
|
||||
public const PRE_UPDATE_EVENT = 'entity_manager_event.pre_update';
|
||||
public const PRE_DELETE_EVENT = 'entity_manager_event.pre_delete';
|
||||
|
||||
protected EntityInterface $entity;
|
||||
|
||||
public function __construct(EntityInterface $entity)
|
||||
public function __construct(protected EntityInterface $entity)
|
||||
{
|
||||
$this->entity = $entity;
|
||||
}
|
||||
|
||||
public function getEntity(): EntityInterface
|
||||
|
|
|
@ -2,8 +2,8 @@
|
|||
|
||||
namespace App\Core\Event\Page;
|
||||
|
||||
use Symfony\Contracts\EventDispatcher\Event;
|
||||
use App\Core\Entity\Site\Page\Page;
|
||||
use Symfony\Contracts\EventDispatcher\Event;
|
||||
|
||||
/**
|
||||
* class PageEditEvent.
|
||||
|
@ -12,14 +12,12 @@ use App\Core\Entity\Site\Page\Page;
|
|||
*/
|
||||
class PageEditEvent extends Event
|
||||
{
|
||||
const FORM_INIT_EVENT = 'page_edit_event.form_init';
|
||||
public const FORM_INIT_EVENT = 'page_edit_event.form_init';
|
||||
|
||||
protected Page $page;
|
||||
protected array $pageBuilderOptions = [];
|
||||
|
||||
public function __construct(Page $page)
|
||||
public function __construct(protected Page $page)
|
||||
{
|
||||
$this->page = $page;
|
||||
}
|
||||
|
||||
public function getPage()
|
||||
|
|
|
@ -11,14 +11,11 @@ use Symfony\Contracts\EventDispatcher\Event;
|
|||
*/
|
||||
class NavigationSettingEvent extends Event
|
||||
{
|
||||
const INIT_EVENT = 'navigation_setting_event.init';
|
||||
const FORM_INIT_EVENT = 'navigation_setting_event.form_init';
|
||||
public const INIT_EVENT = 'navigation_setting_event.init';
|
||||
public const FORM_INIT_EVENT = 'navigation_setting_event.form_init';
|
||||
|
||||
protected $data;
|
||||
|
||||
public function __construct($data = null)
|
||||
public function __construct(protected $data = null)
|
||||
{
|
||||
$this->data = $data;
|
||||
}
|
||||
|
||||
public function getData()
|
||||
|
|
|
@ -11,14 +11,11 @@ use Symfony\Contracts\EventDispatcher\Event;
|
|||
*/
|
||||
class SettingEvent extends Event
|
||||
{
|
||||
const INIT_EVENT = 'setting_event.init';
|
||||
const FORM_INIT_EVENT = 'setting_event.form_init';
|
||||
public const INIT_EVENT = 'setting_event.init';
|
||||
public const FORM_INIT_EVENT = 'setting_event.form_init';
|
||||
|
||||
protected $data;
|
||||
|
||||
public function __construct($data = null)
|
||||
public function __construct(protected $data = null)
|
||||
{
|
||||
$this->data = $data;
|
||||
}
|
||||
|
||||
public function getData()
|
||||
|
|
|
@ -11,7 +11,7 @@ use Symfony\Contracts\EventDispatcher\Event;
|
|||
*/
|
||||
class TaskInitEvent extends Event
|
||||
{
|
||||
const INIT_EVENT = 'task_event.init';
|
||||
public const INIT_EVENT = 'task_event.init';
|
||||
|
||||
protected array $tasks = [];
|
||||
|
||||
|
|
|
@ -14,17 +14,13 @@ use Symfony\Contracts\EventDispatcher\Event;
|
|||
*/
|
||||
class TaskRunRequestedEvent extends Event
|
||||
{
|
||||
const RUN_REQUEST_EVENT = 'task_event.run_request';
|
||||
public const RUN_REQUEST_EVENT = 'task_event.run_request';
|
||||
|
||||
protected string $task;
|
||||
protected InputBag $parameters;
|
||||
protected BufferedOutput $output;
|
||||
|
||||
public function __construct(string $task, InputBag $parameters, BufferedOutput $output)
|
||||
{
|
||||
$this->task = $task;
|
||||
$this->parameters = $parameters;
|
||||
$this->output = $output;
|
||||
public function __construct(
|
||||
protected string $task,
|
||||
protected InputBag $parameters,
|
||||
protected BufferedOutput $output
|
||||
) {
|
||||
}
|
||||
|
||||
public function getTask(): string
|
||||
|
|
|
@ -6,7 +6,6 @@ use App\Core\Ab\AbContainer;
|
|||
use App\Core\Ab\AbTest;
|
||||
use App\Core\Entity\Site\Node;
|
||||
use App\Core\Event\Ab\AbTestEvent;
|
||||
use App\Core\Repository\Site\NodeRepository;
|
||||
use App\Core\Site\SiteRequest;
|
||||
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
|
||||
use Symfony\Component\HttpFoundation\Cookie;
|
||||
|
@ -21,19 +20,13 @@ use Symfony\Component\HttpKernel\Event\ResponseEvent;
|
|||
*/
|
||||
class AbListener
|
||||
{
|
||||
protected EventDispatcherInterface $eventDispatcher;
|
||||
protected AbContainer $container;
|
||||
protected SiteRequest $siteRequest;
|
||||
protected ?Node $node;
|
||||
|
||||
public function __construct(
|
||||
AbContainer $container,
|
||||
EventDispatcherInterface $eventDispatcher,
|
||||
SiteRequest $siteRequest
|
||||
protected AbContainer $container,
|
||||
protected EventDispatcherInterface $eventDispatcher,
|
||||
protected SiteRequest $siteRequest
|
||||
) {
|
||||
$this->eventDispatcher = $eventDispatcher;
|
||||
$this->container = $container;
|
||||
$this->siteRequest = $siteRequest;
|
||||
}
|
||||
|
||||
public function onKernelRequest(RequestEvent $event)
|
||||
|
@ -70,6 +63,16 @@ class AbListener
|
|||
}
|
||||
}
|
||||
|
||||
public function onKernelResponse(ResponseEvent $event)
|
||||
{
|
||||
$cookies = $event->getRequest()->attributes->get('ab_test_cookies', []);
|
||||
|
||||
foreach ($cookies as $name => $value) {
|
||||
$cookie = Cookie::create($name, $value['value'], time() + $value['duration']);
|
||||
$event->getResponse()->headers->setCookie($cookie);
|
||||
}
|
||||
}
|
||||
|
||||
protected function getCookieName(): string
|
||||
{
|
||||
return 'ab_test_'.$this->getAbTestCode();
|
||||
|
@ -96,14 +99,4 @@ class AbListener
|
|||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function onKernelResponse(ResponseEvent $event)
|
||||
{
|
||||
$cookies = $event->getRequest()->attributes->get('ab_test_cookies', []);
|
||||
|
||||
foreach ($cookies as $name => $value) {
|
||||
$cookie = Cookie::create($name, $value['value'], time() + $value['duration']);
|
||||
$event->getResponse()->headers->setCookie($cookie);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,30 +23,18 @@ use Symfony\Component\HttpKernel\Event\RequestEvent;
|
|||
*/
|
||||
class AnalyticListener
|
||||
{
|
||||
protected NodeRepository $nodeRepository;
|
||||
protected ViewRepositoryQuery $viewRepositoryQuery;
|
||||
protected ViewFactory $viewFactory;
|
||||
protected RefererRepositoryQuery $refererRepositoryQuery;
|
||||
protected RefererFactory $refererFactory;
|
||||
protected EntityManager $manager;
|
||||
protected DeviceDetector $deviceDetector;
|
||||
protected Request $request;
|
||||
protected Node $node;
|
||||
|
||||
public function __construct(
|
||||
NodeRepository $nodeRepository,
|
||||
ViewRepositoryQuery $viewRepositoryQuery,
|
||||
ViewFactory $viewFactory,
|
||||
RefererRepositoryQuery $refererRepositoryQuery,
|
||||
RefererFactory $refererFactory,
|
||||
EntityManager $manager
|
||||
protected NodeRepository $nodeRepository,
|
||||
protected ViewRepositoryQuery $viewRepositoryQuery,
|
||||
protected ViewFactory $viewFactory,
|
||||
protected RefererRepositoryQuery $refererRepositoryQuery,
|
||||
protected RefererFactory $refererFactory,
|
||||
protected EntityManager $manager
|
||||
) {
|
||||
$this->nodeRepository = $nodeRepository;
|
||||
$this->viewRepositoryQuery = $viewRepositoryQuery;
|
||||
$this->viewFactory = $viewFactory;
|
||||
$this->refererRepositoryQuery = $refererRepositoryQuery;
|
||||
$this->refererFactory = $refererFactory;
|
||||
$this->manager = $manager;
|
||||
$this->createDeviceDetector();
|
||||
}
|
||||
|
||||
|
|
|
@ -3,11 +3,10 @@
|
|||
namespace App\Core\EventListener;
|
||||
|
||||
use App\Core\Repository\RedirectRepositoryQuery;
|
||||
use App\Core\Router\RedirectBuilder;
|
||||
use App\Core\Router\RedirectMatcher;
|
||||
use Symfony\Component\HttpFoundation\RedirectResponse;
|
||||
use Symfony\Component\HttpKernel\Event\ExceptionEvent;
|
||||
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
|
||||
use App\Core\Router\RedirectBuilder;
|
||||
|
||||
/**
|
||||
* class RedirectListener.
|
||||
|
@ -16,15 +15,11 @@ use App\Core\Router\RedirectBuilder;
|
|||
*/
|
||||
class RedirectListener
|
||||
{
|
||||
protected RedirectMatcher $matcher;
|
||||
protected RedirectBuilder $builder;
|
||||
protected RedirectRepositoryQuery $repository;
|
||||
|
||||
public function __construct(RedirectMatcher $matcher, RedirectBuilder $builder, RedirectRepositoryQuery $repository)
|
||||
{
|
||||
$this->matcher = $matcher;
|
||||
$this->builder = $builder;
|
||||
$this->repository = $repository;
|
||||
public function __construct(
|
||||
protected RedirectMatcher $matcher,
|
||||
protected RedirectBuilder $builder,
|
||||
protected RedirectRepositoryQuery $repository
|
||||
) {
|
||||
}
|
||||
|
||||
public function onKernelException(ExceptionEvent $event)
|
||||
|
@ -37,7 +32,7 @@ class RedirectListener
|
|||
|
||||
$redirects = $this->repository
|
||||
->orderBy('.sortOrder')
|
||||
->where('.isEnabled=1')
|
||||
->where('.isEnabled=true')
|
||||
->find()
|
||||
;
|
||||
|
||||
|
|
|
@ -17,24 +17,13 @@ use Symfony\Contracts\Translation\TranslatorInterface;
|
|||
*/
|
||||
class PasswordRequestEventSubscriber implements EventSubscriberInterface
|
||||
{
|
||||
protected MailNotifier $notifier;
|
||||
protected UrlGeneratorInterface $urlGenerator;
|
||||
protected EntityManager $entityManager;
|
||||
protected TokenGeneratorInterface $tokenGenerator;
|
||||
protected TranslatorInterface $translator;
|
||||
|
||||
public function __construct(
|
||||
MailNotifier $notifier,
|
||||
UrlGeneratorInterface $urlGenerator,
|
||||
EntityManager $entityManager,
|
||||
TokenGeneratorInterface $tokenGenerator,
|
||||
TranslatorInterface $translator
|
||||
protected MailNotifier $notifier,
|
||||
protected UrlGeneratorInterface $urlGenerator,
|
||||
protected EntityManager $entityManager,
|
||||
protected TokenGeneratorInterface $tokenGenerator,
|
||||
protected TranslatorInterface $translator
|
||||
) {
|
||||
$this->notifier = $notifier;
|
||||
$this->urlGenerator = $urlGenerator;
|
||||
$this->entityManager = $entityManager;
|
||||
$this->tokenGenerator = $tokenGenerator;
|
||||
$this->translator = $translator;
|
||||
}
|
||||
|
||||
public static function getSubscribedEvents()
|
||||
|
|
|
@ -16,12 +16,12 @@ use Symfony\Component\Security\Core\Exception\AccessDeniedException;
|
|||
*/
|
||||
class RequestSecurityEventSubscriber implements EventSubscriberInterface
|
||||
{
|
||||
protected NodeRepository $nodeRepository;
|
||||
protected AuthorizationChecker $authorizationChecker;
|
||||
|
||||
public function __construct(NodeRepository $nodeRepository, ContainerInterface $container)
|
||||
{
|
||||
$this->nodeRepository = $nodeRepository;
|
||||
public function __construct(
|
||||
protected NodeRepository $nodeRepository,
|
||||
ContainerInterface $container
|
||||
) {
|
||||
$this->authorizationChecker = $container->get('security.authorization_checker');
|
||||
}
|
||||
|
||||
|
|
|
@ -4,18 +4,15 @@ namespace App\Core\EventSubscriber\Site;
|
|||
|
||||
use App\Core\Site\SiteRequest;
|
||||
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
|
||||
use Symfony\Component\HttpKernel\KernelEvents;
|
||||
use Symfony\Component\HttpKernel\Event\ResponseEvent;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\HttpKernel\Event\ResponseEvent;
|
||||
use Symfony\Component\HttpKernel\KernelEvents;
|
||||
use function Symfony\Component\String\u;
|
||||
|
||||
class ForcedDomainEventSubscriber implements EventSubscriberInterface
|
||||
{
|
||||
protected SiteRequest $siteRequest;
|
||||
|
||||
public function __construct(SiteRequest $siteRequest)
|
||||
public function __construct(protected SiteRequest $siteRequest)
|
||||
{
|
||||
$this->siteRequest = $siteRequest;
|
||||
}
|
||||
|
||||
public function onKernelResponse(ResponseEvent $event)
|
||||
|
@ -38,7 +35,8 @@ class ForcedDomainEventSubscriber implements EventSubscriberInterface
|
|||
->replace(
|
||||
'://'.$this->siteRequest->getDomain(),
|
||||
'://'.$navigation->getDomain()
|
||||
);
|
||||
)
|
||||
;
|
||||
|
||||
$event->getResponse()->headers->set('Location', $uri);
|
||||
$event->getResponse()->setStatusCode(Response::HTTP_MOVED_PERMANENTLY);
|
||||
|
|
|
@ -20,27 +20,14 @@ use Symfony\Contracts\Translation\TranslatorInterface;
|
|||
*/
|
||||
class MenuEventSubscriber extends EntityManagerEventSubscriber
|
||||
{
|
||||
protected NodeFactory $nodeFactory;
|
||||
protected NodeRepository $nodeRepository;
|
||||
protected EntityManager $entityManager;
|
||||
protected CodeSlugify $slugify;
|
||||
protected SymfonyCacheManager $cacheManager;
|
||||
protected TranslatorInterface $translation;
|
||||
|
||||
public function __construct(
|
||||
NodeFactory $nodeFactory,
|
||||
NodeRepository $nodeRepository,
|
||||
EntityManager $entityManager,
|
||||
CodeSlugify $slugify,
|
||||
SymfonyCacheManager $cacheManager,
|
||||
TranslatorInterface $translator
|
||||
protected NodeFactory $nodeFactory,
|
||||
protected NodeRepository $nodeRepository,
|
||||
protected EntityManager $entityManager,
|
||||
protected CodeSlugify $slugify,
|
||||
protected SymfonyCacheManager $cacheManager,
|
||||
protected TranslatorInterface $translator
|
||||
) {
|
||||
$this->nodeFactory = $nodeFactory;
|
||||
$this->nodeRepository = $nodeRepository;
|
||||
$this->entityManager = $entityManager;
|
||||
$this->slugify = $slugify;
|
||||
$this->cacheManager = $cacheManager;
|
||||
$this->translator = $translator;
|
||||
}
|
||||
|
||||
public function supports(EntityInterface $entity): bool
|
||||
|
|
|
@ -17,11 +17,9 @@ use App\Core\Slugify\CodeSlugify;
|
|||
class NavigationEventSubscriber extends EntityManagerEventSubscriber
|
||||
{
|
||||
public function __construct(
|
||||
EntityManager $entityManager,
|
||||
CodeSlugify $slugify
|
||||
protected EntityManager $entityManager,
|
||||
protected CodeSlugify $slugify
|
||||
) {
|
||||
$this->entityManager = $entityManager;
|
||||
$this->slugify = $slugify;
|
||||
}
|
||||
|
||||
public function supports(EntityInterface $entity): bool
|
||||
|
|
|
@ -12,7 +12,6 @@ use App\Core\Repository\Site\NodeRepository;
|
|||
use App\Core\Slugify\CodeSlugify;
|
||||
use App\Core\Slugify\RouteParameterSlugify;
|
||||
use App\Core\Slugify\Slugify;
|
||||
use Symfony\Component\HttpKernel\KernelInterface;
|
||||
use function Symfony\Component\String\u;
|
||||
|
||||
/**
|
||||
|
@ -22,27 +21,14 @@ use function Symfony\Component\String\u;
|
|||
*/
|
||||
class NodeEventSubscriber extends EntityManagerEventSubscriber
|
||||
{
|
||||
protected NodeFactory $nodeFactory;
|
||||
protected EntityManager $entityManager;
|
||||
protected KernelInterface $kernel;
|
||||
protected Slugify $slugify;
|
||||
protected CodeSlugify $codeSlugify;
|
||||
protected RouteParameterSlugify $routeParameterSlugify;
|
||||
|
||||
public function __construct(
|
||||
NodeFactory $nodeFactory,
|
||||
NodeRepository $nodeRepository,
|
||||
EntityManager $entityManager,
|
||||
Slugify $slugify,
|
||||
CodeSlugify $codeSlugify,
|
||||
RouteParameterSlugify $routeParameterSlugify
|
||||
protected NodeFactory $nodeFactory,
|
||||
protected NodeRepository $nodeRepository,
|
||||
protected EntityManager $entityManager,
|
||||
protected Slugify $slugify,
|
||||
protected CodeSlugify $codeSlugify,
|
||||
protected RouteParameterSlugify $routeParameterSlugify
|
||||
) {
|
||||
$this->nodeFactory = $nodeFactory;
|
||||
$this->nodeRepository = $nodeRepository;
|
||||
$this->entityManager = $entityManager;
|
||||
$this->slugify = $slugify;
|
||||
$this->codeSlugify = $codeSlugify;
|
||||
$this->routeParameterSlugify = $routeParameterSlugify;
|
||||
}
|
||||
|
||||
public function supports(EntityInterface $entity): bool
|
||||
|
@ -63,7 +49,7 @@ class NodeEventSubscriber extends EntityManagerEventSubscriber
|
|||
|
||||
$node = $event->getEntity();
|
||||
|
||||
$node->setCode($this->codeSlugify->slugify($node->getCode()));
|
||||
$node->setCode($this->codeSlugify->slugify($node->getCode() ?? ''));
|
||||
|
||||
if ($node->getDisableUrl()) {
|
||||
$node->setUrl(null);
|
||||
|
|
|
@ -17,11 +17,8 @@ use Symfony\Component\HttpFoundation\File\UploadedFile;
|
|||
*/
|
||||
class BlockEventSubscriber extends EntityManagerEventSubscriber
|
||||
{
|
||||
protected FileUploadHandler $fileUpload;
|
||||
|
||||
public function __construct(FileUploadHandler $fileUpload)
|
||||
public function __construct(protected FileUploadHandler $fileUpload)
|
||||
{
|
||||
$this->fileUpload = $fileUpload;
|
||||
}
|
||||
|
||||
public function supports(EntityInterface $entity): bool
|
||||
|
|
|
@ -16,11 +16,8 @@ use Symfony\Component\HttpFoundation\File\UploadedFile;
|
|||
*/
|
||||
class PageEventSubscriber extends EntityManagerEventSubscriber
|
||||
{
|
||||
protected FileUploadHandler $fileUpload;
|
||||
|
||||
public function __construct(FileUploadHandler $fileUpload)
|
||||
public function __construct(protected FileUploadHandler $fileUpload)
|
||||
{
|
||||
$this->fileUpload = $fileUpload;
|
||||
}
|
||||
|
||||
public function supports(EntityInterface $entity): bool
|
||||
|
|
|
@ -18,13 +18,10 @@ use Symfony\Component\HttpKernel\KernelInterface;
|
|||
*/
|
||||
class SiteEventSubscriber extends EntityManagerEventSubscriber
|
||||
{
|
||||
protected KernelInterface $kernel;
|
||||
protected SymfonyCacheManager $cacheManager;
|
||||
|
||||
public function __construct(KernelInterface $kernel, SymfonyCacheManager $cacheManager)
|
||||
{
|
||||
$this->kernel = $kernel;
|
||||
$this->cacheManager = $cacheManager;
|
||||
public function __construct(
|
||||
protected KernelInterface $kernel,
|
||||
protected SymfonyCacheManager $cacheManager
|
||||
) {
|
||||
}
|
||||
|
||||
public function supports(EntityInterface $entity): bool
|
||||
|
|
|
@ -13,11 +13,8 @@ use App\Core\Event\Task\TaskRunRequestedEvent;
|
|||
*/
|
||||
class CacheCleanTaskEventSubscriber extends TaskEventSubscriber
|
||||
{
|
||||
protected SymfonyCacheManager $cacheManager;
|
||||
|
||||
public function __construct(SymfonyCacheManager $cacheManager)
|
||||
public function __construct(protected SymfonyCacheManager $cacheManager)
|
||||
{
|
||||
$this->cacheManager = $cacheManager;
|
||||
}
|
||||
|
||||
public function onInit(TaskInitEvent $event)
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
|
||||
namespace App\Core\Factory;
|
||||
|
||||
use App\Core\Factory\FactoryInterface;
|
||||
use App\Core\Entity\Redirect as Entity;
|
||||
|
||||
class RedirectFactory implements FactoryInterface
|
||||
|
|
|
@ -23,22 +23,15 @@ class FsFileManager
|
|||
protected string $path;
|
||||
protected string $pathUri;
|
||||
protected array $pathLocked;
|
||||
protected FileUploadHandler $uploadHandler;
|
||||
protected FileInformationFactory $fileInformationFactory;
|
||||
protected FileInformationRepositoryQuery $fileInformationRepositoryQuery;
|
||||
|
||||
public function __construct(
|
||||
ParameterBagInterface $params,
|
||||
FileUploadHandler $uploadHandler,
|
||||
FileInformationFactory $fileInformationFactory,
|
||||
FileInformationRepositoryQuery $fileInformationRepositoryQuery
|
||||
protected FileUploadHandler $uploadHandler,
|
||||
protected FileInformationFactory $fileInformationFactory,
|
||||
protected FileInformationRepositoryQuery $fileInformationRepositoryQuery
|
||||
) {
|
||||
$config = $params->get('core')['file_manager'];
|
||||
|
||||
$this->uploadHandler = $uploadHandler;
|
||||
$this->fileInformationFactory = $fileInformationFactory;
|
||||
$this->fileInformationRepositoryQuery = $fileInformationRepositoryQuery;
|
||||
|
||||
$this->mimes = $config['mimes'];
|
||||
$this->path = $config['path'];
|
||||
$this->pathUri = $this->normalizePath($config['path_uri']);
|
||||
|
@ -301,14 +294,16 @@ class FsFileManager
|
|||
|
||||
protected function applySort(Finder $finder, string $sort, string $direction)
|
||||
{
|
||||
if ('name' === $sort) {
|
||||
$finder->sortByName();
|
||||
} elseif ('updated_date' === $sort) {
|
||||
$finder->sortByModifiedTime();
|
||||
}
|
||||
$sorts = [
|
||||
'name' => 'sortByName',
|
||||
'type' => 'sortByType',
|
||||
'updated_at' => 'sortByModifiedTime',
|
||||
];
|
||||
|
||||
if ('desc' === $direction) {
|
||||
$finder->reverseSorting();
|
||||
$finder->{$sorts[$sort]}()->reverseSorting();
|
||||
} else {
|
||||
$finder->{$sorts[$sort]}();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -6,7 +6,6 @@ use Symfony\Component\Form\AbstractType;
|
|||
use Symfony\Component\Form\Extension\Core\Type\TextType;
|
||||
use Symfony\Component\Form\FormInterface;
|
||||
use Symfony\Component\Form\FormView;
|
||||
use Symfony\Component\Form\Extension\Core\Type\HiddenType;
|
||||
|
||||
class FilePickerType extends AbstractType
|
||||
{
|
||||
|
|
|
@ -11,6 +11,15 @@ use Symfony\Component\HttpFoundation\File\UploadedFile;
|
|||
*/
|
||||
class FileUploadHandler
|
||||
{
|
||||
protected $filenameGenerator;
|
||||
|
||||
public function setFilenameGenerator(callable $filenameGenerator): self
|
||||
{
|
||||
$this->filenameGenerator = $filenameGenerator;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function handleForm(?UploadedFile $uploadedFile, string $path, ?callable $afterUploadCallback = null, bool $keepOriginalFilename = false): void
|
||||
{
|
||||
if (null === $uploadedFile) {
|
||||
|
@ -21,9 +30,11 @@ class FileUploadHandler
|
|||
|
||||
if ($keepOriginalFilename) {
|
||||
$filename = $originalFilename.'.'.$uploadedFile->guessExtension();
|
||||
} else {
|
||||
} elseif (!is_callable($this->filenameGenerator)) {
|
||||
$safeFilename = transliterator_transliterate('Any-Latin; Latin-ASCII; [^A-Za-z0-9_] remove; Lower()', $originalFilename);
|
||||
$filename = date('Ymd-his').$safeFilename.'.'.$uploadedFile->guessExtension();
|
||||
} else {
|
||||
$filename = call_user_func($this->filenameGenerator, $uploadedFile);
|
||||
}
|
||||
|
||||
$uploadedFile->move($path, $filename);
|
||||
|
|
|
@ -2,13 +2,11 @@
|
|||
|
||||
namespace App\Core\Form\Filter;
|
||||
|
||||
use App\Core\Entity\Redirect;
|
||||
use Symfony\Component\Form\AbstractType;
|
||||
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
|
||||
use Symfony\Component\Form\Extension\Core\Type\TextType;
|
||||
use Symfony\Component\Form\FormBuilderInterface;
|
||||
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||
use Symfony\Component\Validator\Constraints\NotBlank;
|
||||
|
||||
class RedirectFilterType extends AbstractType
|
||||
{
|
||||
|
|
|
@ -4,12 +4,12 @@ namespace App\Core\Form;
|
|||
|
||||
use App\Core\Entity\Redirect;
|
||||
use Symfony\Component\Form\AbstractType;
|
||||
use Symfony\Component\Form\Extension\Core\Type\CheckboxType;
|
||||
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
|
||||
use Symfony\Component\Form\Extension\Core\Type\TextType;
|
||||
use Symfony\Component\Form\FormBuilderInterface;
|
||||
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||
use Symfony\Component\Validator\Constraints\NotBlank;
|
||||
use Symfony\Component\Form\Extension\Core\Type\CheckboxType;
|
||||
|
||||
class RedirectType extends AbstractType
|
||||
{
|
||||
|
|
|
@ -7,6 +7,7 @@ use Symfony\Component\Form\AbstractType;
|
|||
use Symfony\Component\Form\Extension\Core\Type\TextType;
|
||||
use Symfony\Component\Form\FormBuilderInterface;
|
||||
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||
use Symfony\Component\Validator\Constraints\Length;
|
||||
use Symfony\Component\Validator\Constraints\NotBlank;
|
||||
|
||||
class MenuType extends AbstractType
|
||||
|
@ -23,6 +24,7 @@ class MenuType extends AbstractType
|
|||
],
|
||||
'constraints' => [
|
||||
new NotBlank(),
|
||||
new Length(max: 255),
|
||||
],
|
||||
]
|
||||
);
|
||||
|
@ -37,6 +39,7 @@ class MenuType extends AbstractType
|
|||
],
|
||||
'constraints' => [
|
||||
new NotBlank(),
|
||||
new Length(max: 255),
|
||||
],
|
||||
]
|
||||
);
|
||||
|
|
|
@ -7,6 +7,7 @@ use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
|
|||
use Symfony\Component\Form\Extension\Core\Type\TextType;
|
||||
use Symfony\Component\Form\FormBuilderInterface;
|
||||
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||
use Symfony\Component\Validator\Constraints\Length;
|
||||
use Symfony\Component\Validator\Constraints\NotBlank;
|
||||
|
||||
class NavigationAdditionalDomainType extends AbstractType
|
||||
|
@ -24,6 +25,7 @@ class NavigationAdditionalDomainType extends AbstractType
|
|||
],
|
||||
'constraints' => [
|
||||
new NotBlank(),
|
||||
new Length(max: 255),
|
||||
],
|
||||
]
|
||||
);
|
||||
|
|
|
@ -6,6 +6,7 @@ use App\Core\Entity\Site\Navigation;
|
|||
use Symfony\Component\Form\AbstractType;
|
||||
use Symfony\Component\Form\Extension\Core\Type\CheckboxType;
|
||||
use Symfony\Component\Form\Extension\Core\Type\CollectionType;
|
||||
use Symfony\Component\Form\Extension\Core\Type\ColorType;
|
||||
use Symfony\Component\Form\Extension\Core\Type\TextType;
|
||||
use Symfony\Component\Form\FormBuilderInterface;
|
||||
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||
|
@ -26,6 +27,7 @@ class NavigationType extends AbstractType
|
|||
],
|
||||
'constraints' => [
|
||||
new NotBlank(),
|
||||
new Length(max: 255),
|
||||
],
|
||||
]
|
||||
);
|
||||
|
@ -38,6 +40,21 @@ class NavigationType extends AbstractType
|
|||
'required' => true,
|
||||
'attr' => [
|
||||
],
|
||||
'constraints' => [
|
||||
new NotBlank(),
|
||||
new Length(max: 255),
|
||||
],
|
||||
]
|
||||
);
|
||||
|
||||
$builder->add(
|
||||
'color',
|
||||
ColorType::class,
|
||||
[
|
||||
'label' => 'Color',
|
||||
'required' => true,
|
||||
'attr' => [
|
||||
],
|
||||
'constraints' => [
|
||||
new NotBlank(),
|
||||
],
|
||||
|
@ -54,6 +71,7 @@ class NavigationType extends AbstractType
|
|||
],
|
||||
'constraints' => [
|
||||
new NotBlank(),
|
||||
new Length(max: 255),
|
||||
],
|
||||
]
|
||||
);
|
||||
|
@ -94,7 +112,7 @@ class NavigationType extends AbstractType
|
|||
],
|
||||
'constraints' => [
|
||||
new NotBlank(),
|
||||
new Length(['min' => 2, 'max' => 10]),
|
||||
new Length(min: 2, max: 10),
|
||||
],
|
||||
]
|
||||
);
|
||||
|
|
|
@ -13,6 +13,7 @@ use Symfony\Component\Form\Extension\Core\Type\CollectionType;
|
|||
use Symfony\Component\Form\Extension\Core\Type\TextType;
|
||||
use Symfony\Component\Form\FormBuilderInterface;
|
||||
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||
use Symfony\Component\Validator\Constraints\Length;
|
||||
use Symfony\Component\Validator\Constraints\NotBlank;
|
||||
|
||||
class NodeType extends AbstractType
|
||||
|
@ -29,6 +30,7 @@ class NodeType extends AbstractType
|
|||
],
|
||||
'constraints' => [
|
||||
new NotBlank(),
|
||||
new Length(max: 255),
|
||||
],
|
||||
]
|
||||
);
|
||||
|
@ -43,6 +45,7 @@ class NodeType extends AbstractType
|
|||
'attr' => [
|
||||
],
|
||||
'constraints' => [
|
||||
new Length(max: 255),
|
||||
],
|
||||
]
|
||||
);
|
||||
|
@ -82,6 +85,7 @@ class NodeType extends AbstractType
|
|||
'attr' => [
|
||||
],
|
||||
'constraints' => [
|
||||
new Length(max: 255),
|
||||
],
|
||||
]
|
||||
);
|
||||
|
@ -116,6 +120,9 @@ class NodeType extends AbstractType
|
|||
|
||||
return $choices;
|
||||
}),
|
||||
'constraints' => [
|
||||
new Length(max: 255),
|
||||
],
|
||||
]
|
||||
);
|
||||
|
||||
|
|
|
@ -2,11 +2,11 @@
|
|||
|
||||
namespace App\Core\Form\Site\Page;
|
||||
|
||||
use App\Core\Entity\Site\Page\Block;
|
||||
use App\Core\Form\FileManager\FilePickerType;
|
||||
use Symfony\Component\Form\AbstractType;
|
||||
use Symfony\Component\Form\FormBuilderInterface;
|
||||
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||
use Symfony\Component\Form\AbstractType;
|
||||
use App\Core\Entity\Site\Page\Block;
|
||||
|
||||
class FilePickerBlockType extends AbstractType
|
||||
{
|
||||
|
|
|
@ -6,10 +6,10 @@ use App\Core\Entity\Site\Navigation;
|
|||
use Doctrine\ORM\EntityRepository;
|
||||
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
|
||||
use Symfony\Component\Form\AbstractType;
|
||||
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
|
||||
use Symfony\Component\Form\Extension\Core\Type\TextType;
|
||||
use Symfony\Component\Form\FormBuilderInterface;
|
||||
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
|
||||
|
||||
class PageFilterType extends AbstractType
|
||||
{
|
||||
|
|
|
@ -10,6 +10,7 @@ use Symfony\Component\Form\Extension\Core\Type\TextType;
|
|||
use Symfony\Component\Form\FormBuilderInterface;
|
||||
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||
use Symfony\Component\Validator\Constraints\Image;
|
||||
use Symfony\Component\Validator\Constraints\Length;
|
||||
use Symfony\Component\Validator\Constraints\NotBlank;
|
||||
|
||||
class PageType extends AbstractType
|
||||
|
@ -26,6 +27,7 @@ class PageType extends AbstractType
|
|||
],
|
||||
'constraints' => [
|
||||
new NotBlank(),
|
||||
new Length(max: 255),
|
||||
],
|
||||
]
|
||||
);
|
||||
|
@ -39,6 +41,7 @@ class PageType extends AbstractType
|
|||
'attr' => [
|
||||
],
|
||||
'constraints' => [
|
||||
new Length(max: 255),
|
||||
],
|
||||
]
|
||||
);
|
||||
|
@ -52,6 +55,7 @@ class PageType extends AbstractType
|
|||
'attr' => [
|
||||
],
|
||||
'constraints' => [
|
||||
new Length(max: 255),
|
||||
],
|
||||
]
|
||||
);
|
||||
|
@ -65,6 +69,7 @@ class PageType extends AbstractType
|
|||
'attr' => [
|
||||
],
|
||||
'constraints' => [
|
||||
new Length(max: 255),
|
||||
],
|
||||
]
|
||||
);
|
||||
|
@ -78,6 +83,7 @@ class PageType extends AbstractType
|
|||
'attr' => [
|
||||
],
|
||||
'constraints' => [
|
||||
new Length(max: 255),
|
||||
],
|
||||
]
|
||||
);
|
||||
|
|
|
@ -20,6 +20,10 @@ class CollectionType extends BaseCollectionType
|
|||
'collection_name' => $options['collection_name'],
|
||||
'label_add' => $options['label_add'],
|
||||
'label_delete' => $options['label_delete'],
|
||||
'allow_add' => $options['allow_add'],
|
||||
'allow_delete' => $options['allow_delete'],
|
||||
'template_before_item' => $options['template_before_item'],
|
||||
'template_after_item' => $options['template_after_item'],
|
||||
]);
|
||||
}
|
||||
|
||||
|
@ -31,6 +35,8 @@ class CollectionType extends BaseCollectionType
|
|||
'collection_name' => '',
|
||||
'label_add' => 'Add',
|
||||
'label_delete' => 'Delete',
|
||||
'template_before_item' => null,
|
||||
'template_after_item' => null,
|
||||
]);
|
||||
}
|
||||
|
||||
|
|
|
@ -11,6 +11,7 @@ use Symfony\Bundle\MakerBundle\Maker\AbstractMaker;
|
|||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Filesystem\Filesystem;
|
||||
use function Symfony\Component\String\u;
|
||||
|
||||
class MakeCrudController extends AbstractMaker
|
||||
|
@ -103,6 +104,17 @@ class MakeCrudController extends AbstractMaker
|
|||
$options
|
||||
);
|
||||
|
||||
$views = ['_form.html.twig', '_show.html.twig'];
|
||||
$directory = sprintf('templates/admin/%s_admin/', $options['route']);
|
||||
$filesystem = new Filesystem();
|
||||
$filesystem->mkdir($directory);
|
||||
foreach ($views as $view) {
|
||||
$filesystem->dumpFile(
|
||||
$directory.$view,
|
||||
sprintf("{{ include('@Core/admin/crud/%s') }}\n", $view)
|
||||
);
|
||||
}
|
||||
|
||||
$generator->writeChanges();
|
||||
|
||||
$this->writeSuccessMessage($io);
|
||||
|
|
|
@ -11,7 +11,6 @@ use Symfony\Bundle\MakerBundle\Maker\AbstractMaker;
|
|||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use function Symfony\Component\String\u;
|
||||
|
||||
class MakeFactory extends AbstractMaker
|
||||
{
|
||||
|
|
|
@ -8,11 +8,11 @@ use Symfony\Bundle\MakerBundle\DependencyBuilder;
|
|||
use Symfony\Bundle\MakerBundle\Generator;
|
||||
use Symfony\Bundle\MakerBundle\InputConfiguration;
|
||||
use Symfony\Bundle\MakerBundle\Maker\AbstractMaker;
|
||||
use Symfony\Bundle\MakerBundle\Str;
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Question\Question;
|
||||
use Symfony\Bundle\MakerBundle\Str;
|
||||
use Symfony\Component\Filesystem\Filesystem;
|
||||
|
||||
class MakePage extends AbstractMaker
|
||||
|
@ -92,7 +92,8 @@ class MakePage extends AbstractMaker
|
|||
|
||||
$this->writeSuccessMessage($io);
|
||||
$io->text('Register the page in <comment>config/packages/app.yaml</comment>: ');
|
||||
$io->text(<<< EOF
|
||||
$io->text(
|
||||
<<< EOF
|
||||
|
||||
core:
|
||||
site:
|
||||
|
@ -100,10 +101,18 @@ core:
|
|||
{$pageClassNameDetails->getFullName()}:
|
||||
name: {$pageClassNameDetails->getShortName()}
|
||||
templates:
|
||||
- {name: "Default", file: "${templatePath}"}
|
||||
- {name: "Default", file: "{$templatePath}"}
|
||||
|
||||
EOF
|
||||
);
|
||||
);
|
||||
}
|
||||
|
||||
public function configureDependencies(DependencyBuilder $dependencies)
|
||||
{
|
||||
$dependencies->addClassDependency(
|
||||
Annotation::class,
|
||||
'doctrine/annotations'
|
||||
);
|
||||
}
|
||||
|
||||
private function askForNextBlock(ConsoleStyle $io, array $blocks, bool $isFirstField)
|
||||
|
@ -138,7 +147,7 @@ EOF
|
|||
$types = [
|
||||
'text' => null,
|
||||
'textarea' => null,
|
||||
'choice' => null,
|
||||
'choice' => 'BlockEntity\\ChoiceBlock::class',
|
||||
'collection' => 'BlockEntity\\CollectionBlock::class',
|
||||
'editor_js_textarea' => null,
|
||||
'file' => 'BlockEntity\\FileBlock::class',
|
||||
|
@ -183,12 +192,4 @@ EOF
|
|||
$io->writeln(sprintf(' * <comment>%s</comment>', $type));
|
||||
}
|
||||
}
|
||||
|
||||
public function configureDependencies(DependencyBuilder $dependencies)
|
||||
{
|
||||
$dependencies->addClassDependency(
|
||||
Annotation::class,
|
||||
'doctrine/annotations'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,7 +4,6 @@ namespace App\Core\Manager;
|
|||
|
||||
use App\Core\Entity\EntityInterface;
|
||||
use App\Core\Event\EntityManager\EntityManagerEvent;
|
||||
use Doctrine\ORM\EntityManager as DoctrineEntityManager;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
|
||||
|
||||
|
@ -15,23 +14,19 @@ use Symfony\Component\EventDispatcher\EventDispatcherInterface;
|
|||
*/
|
||||
class EntityManager
|
||||
{
|
||||
protected EventDispatcherInterface $eventDispatcher;
|
||||
|
||||
protected DoctrineEntityManager $entityManager;
|
||||
|
||||
public function __construct(EventDispatcherInterface $eventDispatcher, EntityManagerInterface $entityManager)
|
||||
{
|
||||
$this->eventDispatcher = $eventDispatcher;
|
||||
$this->entityManager = $entityManager;
|
||||
public function __construct(
|
||||
protected EventDispatcherInterface $eventDispatcher,
|
||||
protected EntityManagerInterface $entityManager
|
||||
) {
|
||||
}
|
||||
|
||||
public function create(EntityInterface $entity, bool $dispatchEvent = true): self
|
||||
public function create(EntityInterface $entity, bool $dispatchEvent = true, bool $flush = true): self
|
||||
{
|
||||
if ($dispatchEvent) {
|
||||
$this->eventDispatcher->dispatch(new EntityManagerEvent($entity), EntityManagerEvent::PRE_CREATE_EVENT);
|
||||
}
|
||||
|
||||
$this->persist($entity);
|
||||
$this->persist($entity, $flush);
|
||||
|
||||
if ($dispatchEvent) {
|
||||
$this->eventDispatcher->dispatch(new EntityManagerEvent($entity), EntityManagerEvent::CREATE_EVENT);
|
||||
|
@ -40,13 +35,13 @@ class EntityManager
|
|||
return $this;
|
||||
}
|
||||
|
||||
public function update(EntityInterface $entity, bool $dispatchEvent = true): self
|
||||
public function update(EntityInterface $entity, bool $dispatchEvent = true, bool $flush = true): self
|
||||
{
|
||||
if ($dispatchEvent) {
|
||||
$this->eventDispatcher->dispatch(new EntityManagerEvent($entity), EntityManagerEvent::PRE_UPDATE_EVENT);
|
||||
}
|
||||
|
||||
$this->persist($entity);
|
||||
$this->persist($entity, $flush);
|
||||
|
||||
if ($dispatchEvent) {
|
||||
$this->eventDispatcher->dispatch(new EntityManagerEvent($entity), EntityManagerEvent::UPDATE_EVENT);
|
||||
|
@ -55,14 +50,17 @@ class EntityManager
|
|||
return $this;
|
||||
}
|
||||
|
||||
public function delete(EntityInterface $entity, bool $dispatchEvent = true): self
|
||||
public function delete(EntityInterface $entity, bool $dispatchEvent = true, bool $flush = true): self
|
||||
{
|
||||
if ($dispatchEvent) {
|
||||
$this->eventDispatcher->dispatch(new EntityManagerEvent($entity), EntityManagerEvent::PRE_DELETE_EVENT);
|
||||
}
|
||||
|
||||
$this->entityManager->remove($entity);
|
||||
$this->flush();
|
||||
|
||||
if ($flush) {
|
||||
$this->flush();
|
||||
}
|
||||
|
||||
if ($dispatchEvent) {
|
||||
$this->eventDispatcher->dispatch(new EntityManagerEvent($entity), EntityManagerEvent::DELETE_EVENT);
|
||||
|
@ -90,9 +88,12 @@ class EntityManager
|
|||
return $this->entityManager;
|
||||
}
|
||||
|
||||
protected function persist(EntityInterface $entity)
|
||||
protected function persist(EntityInterface $entity, bool $flush = true)
|
||||
{
|
||||
$this->entityManager->persist($entity);
|
||||
$this->flush();
|
||||
|
||||
if ($flush) {
|
||||
$this->flush();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,10 +11,13 @@ use App\Core\Entity\EntityInterface;
|
|||
*/
|
||||
class TranslatableEntityManager extends EntityManager
|
||||
{
|
||||
protected function persist(EntityInterface $entity)
|
||||
protected function persist(EntityInterface $entity, bool $flush = true)
|
||||
{
|
||||
$this->entityManager->persist($entity);
|
||||
$this->entityManager->persist($entity, $flush);
|
||||
$entity->mergeNewTranslations();
|
||||
$this->flush();
|
||||
|
||||
if ($flush) {
|
||||
$this->flush();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
namespace App\Core;
|
||||
|
||||
if (!defined('MURPH_VERSION')) {
|
||||
define('MURPH_VERSION', 'v1.19.0');
|
||||
define('MURPH_VERSION', 'v1.24.1');
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -2,10 +2,10 @@
|
|||
|
||||
namespace App\Core\Notification;
|
||||
|
||||
use App\Entity\User;
|
||||
use Symfony\Bridge\Twig\Mime\TemplatedEmail;
|
||||
use Symfony\Component\Mailer\MailerInterface;
|
||||
use Twig\Environment as TwigEnvironment;
|
||||
use App\Entity\User;
|
||||
|
||||
/**
|
||||
* class MailNotifier.
|
||||
|
@ -14,7 +14,6 @@ use App\Entity\User;
|
|||
*/
|
||||
class MailNotifier
|
||||
{
|
||||
protected MailerInterface $mailer;
|
||||
protected array $attachments = [];
|
||||
protected array $recipients = [];
|
||||
protected array $bccRecipients = [];
|
||||
|
@ -22,10 +21,8 @@ class MailNotifier
|
|||
protected ?string $from = null;
|
||||
protected ?string $replyTo = null;
|
||||
|
||||
public function __construct(TwigEnvironment $twig, MailerInterface $mailer)
|
||||
public function __construct(protected MailerInterface $mailer)
|
||||
{
|
||||
$this->mailer = $mailer;
|
||||
$this->twig = $twig;
|
||||
}
|
||||
|
||||
public function setMailer(Swift_Mailer $mailer): self
|
||||
|
|
|
@ -7,8 +7,8 @@ use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
|
|||
use Doctrine\Persistence\ManagerRegistry;
|
||||
|
||||
/**
|
||||
* @method Referer|null find($id, $lockMode = null, $lockVersion = null)
|
||||
* @method Referer|null findOneBy(array $criteria, array $orderBy = null)
|
||||
* @method null|Referer find($id, $lockMode = null, $lockVersion = null)
|
||||
* @method null|Referer findOneBy(array $criteria, array $orderBy = null)
|
||||
* @method Referer[] findAll()
|
||||
* @method Referer[] findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null)
|
||||
*/
|
||||
|
|
|
@ -3,9 +3,9 @@
|
|||
namespace App\Core\Repository\Analytic;
|
||||
|
||||
use App\Core\Repository\Analytic\RefererRepository as Repository;
|
||||
use App\Core\Repository\RepositoryQuery;
|
||||
use Knp\Component\Pager\PaginatorInterface;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use App\Core\Repository\RepositoryQuery;
|
||||
|
||||
class RefererRepositoryQuery extends RepositoryQuery
|
||||
{
|
||||
|
|
|
@ -7,8 +7,8 @@ use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
|
|||
use Doctrine\Persistence\ManagerRegistry;
|
||||
|
||||
/**
|
||||
* @method View|null find($id, $lockMode = null, $lockVersion = null)
|
||||
* @method View|null findOneBy(array $criteria, array $orderBy = null)
|
||||
* @method null|View find($id, $lockMode = null, $lockVersion = null)
|
||||
* @method null|View findOneBy(array $criteria, array $orderBy = null)
|
||||
* @method View[] findAll()
|
||||
* @method View[] findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null)
|
||||
*/
|
||||
|
|
|
@ -3,9 +3,9 @@
|
|||
namespace App\Core\Repository\Analytic;
|
||||
|
||||
use App\Core\Repository\Analytic\ViewRepository as Repository;
|
||||
use App\Core\Repository\RepositoryQuery;
|
||||
use Knp\Component\Pager\PaginatorInterface;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use App\Core\Repository\RepositoryQuery;
|
||||
|
||||
class ViewRepositoryQuery extends RepositoryQuery
|
||||
{
|
||||
|
|
|
@ -7,8 +7,8 @@ use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
|
|||
use Doctrine\Persistence\ManagerRegistry;
|
||||
|
||||
/**
|
||||
* @method FileInformation|null find($id, $lockMode = null, $lockVersion = null)
|
||||
* @method FileInformation|null findOneBy(array $criteria, array $orderBy = null)
|
||||
* @method null|FileInformation find($id, $lockMode = null, $lockVersion = null)
|
||||
* @method null|FileInformation findOneBy(array $criteria, array $orderBy = null)
|
||||
* @method FileInformation[] findAll()
|
||||
* @method FileInformation[] findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null)
|
||||
*/
|
||||
|
|
|
@ -7,8 +7,8 @@ use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
|
|||
use Doctrine\Persistence\ManagerRegistry;
|
||||
|
||||
/**
|
||||
* @method NavigationSetting|null find($id, $lockMode = null, $lockVersion = null)
|
||||
* @method NavigationSetting|null findOneBy(array $criteria, array $orderBy = null)
|
||||
* @method null|NavigationSetting find($id, $lockMode = null, $lockVersion = null)
|
||||
* @method null|NavigationSetting findOneBy(array $criteria, array $orderBy = null)
|
||||
* @method NavigationSetting[] findAll()
|
||||
* @method NavigationSetting[] findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null)
|
||||
*/
|
||||
|
|
|
@ -7,8 +7,8 @@ use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
|
|||
use Doctrine\Persistence\ManagerRegistry;
|
||||
|
||||
/**
|
||||
* @method Redirect|null find($id, $lockMode = null, $lockVersion = null)
|
||||
* @method Redirect|null findOneBy(array $criteria, array $orderBy = null)
|
||||
* @method null|Redirect find($id, $lockMode = null, $lockVersion = null)
|
||||
* @method null|Redirect findOneBy(array $criteria, array $orderBy = null)
|
||||
* @method Redirect[] findAll()
|
||||
* @method Redirect[] findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null)
|
||||
*/
|
||||
|
|
|
@ -2,9 +2,8 @@
|
|||
|
||||
namespace App\Core\Repository;
|
||||
|
||||
use App\Core\Repository\RepositoryQuery;
|
||||
use Knp\Component\Pager\PaginatorInterface;
|
||||
use App\Core\Repository\RedirectRepository as Repository;
|
||||
use Knp\Component\Pager\PaginatorInterface;
|
||||
|
||||
class RedirectRepositoryQuery extends RepositoryQuery
|
||||
{
|
||||
|
|
|
@ -98,6 +98,26 @@ abstract class RepositoryQuery
|
|||
return $this;
|
||||
}
|
||||
|
||||
public function count()
|
||||
{
|
||||
return $this
|
||||
->select(sprintf('COUNT(%s.id) as total', $this->id))
|
||||
->query
|
||||
->getQuery()
|
||||
->setMaxResults(1)
|
||||
->getOneOrNullResult()['total']
|
||||
;
|
||||
}
|
||||
|
||||
protected function addForcedFilterHandler(string $name): self
|
||||
{
|
||||
if (!in_array($name, $this->forcedFilterHandlers)) {
|
||||
$this->forcedFilterHandlers[] = $name;
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
protected function populateDqlId(&$data)
|
||||
{
|
||||
if (is_string($data)) {
|
||||
|
|
|
@ -7,8 +7,8 @@ use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
|
|||
use Doctrine\Persistence\ManagerRegistry;
|
||||
|
||||
/**
|
||||
* @method Setting|null find($id, $lockMode = null, $lockVersion = null)
|
||||
* @method Setting|null findOneBy(array $criteria, array $orderBy = null)
|
||||
* @method null|Setting find($id, $lockMode = null, $lockVersion = null)
|
||||
* @method null|Setting findOneBy(array $criteria, array $orderBy = null)
|
||||
* @method Setting[] findAll()
|
||||
* @method Setting[] findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null)
|
||||
*/
|
||||
|
|
|
@ -32,9 +32,9 @@ class NodeRepository extends NestedTreeRepository
|
|||
;
|
||||
}
|
||||
|
||||
return $query->getQuery()
|
||||
return null !== $query->getQuery()
|
||||
->setMaxResults(1)
|
||||
->getOneOrNullResult() !== null
|
||||
->getOneOrNullResult()
|
||||
;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,6 +10,19 @@ $pagination-bg: #ffffff !default;
|
|||
$pagination-active-color: #ffffff !default;
|
||||
$pagination-active-bg: #343a40 !default;
|
||||
|
||||
$sidebar-width: 260px !default;
|
||||
|
||||
$input-border-color: map-get($theme-colors, 'dark-blue');
|
||||
$input-btn-focus-color: $input-border-color;
|
||||
|
||||
$component-active-color: map-get($theme-colors, 'dark-blue');
|
||||
|
||||
$nav-tabs-link-active-bg: map-get($theme-colors, 'dark-blue');
|
||||
$nav-pills-link-active-bg: map-get($theme-colors, 'dark-blue');
|
||||
$nav-tabs-link-active-color: lighten(map-get($theme-colors, 'dark-blue'), 100%);
|
||||
$nav-pills-link-active-color: lighten(map-get($theme-colors, 'dark-blue'), 100%);
|
||||
$input-focus-border-color: lighten(map-get($theme-colors, 'dark-blue'), 80%);
|
||||
|
||||
@import "~choices.js/src/styles/choices.scss";
|
||||
@import "~bootstrap/scss/bootstrap.scss";
|
||||
@import "~@fortawesome/fontawesome-free/css/all.css";
|
||||
|
@ -17,9 +30,29 @@ $pagination-active-bg: #343a40 !default;
|
|||
@import '~grapesjs/dist/css/grapes.min.css';
|
||||
@import '~grapesjs-component-code-editor/dist/grapesjs-component-code-editor.min.css';
|
||||
|
||||
@for $i from 1 through 100 {
|
||||
.miw-#{$i*5} {
|
||||
min-width: $i * 5px;
|
||||
@for $i from 1 through 400 {
|
||||
.miw-#{$i}, .min-width-#{$i} {
|
||||
min-width: #{$i}px;
|
||||
}
|
||||
|
||||
.min-width-#{$i}p {
|
||||
min-width: #{$i}#{"%"};
|
||||
}
|
||||
|
||||
.maw-#{$i}, .max-width-#{$i} {
|
||||
max-width: #{$i}px;
|
||||
}
|
||||
|
||||
.max-width-#{$i}p {
|
||||
max-width: #{$i}#{"%"};
|
||||
}
|
||||
|
||||
.width-#{$i} {
|
||||
width: #{$i}px;
|
||||
}
|
||||
|
||||
.width-#{$i}p {
|
||||
width: #{$i}#{"%"};
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -49,6 +82,11 @@ body {
|
|||
display: block;
|
||||
}
|
||||
|
||||
.choices__inner, .is-focused .choices__inner, .is-open .choices__inner {
|
||||
border: 1px solid map-get($theme-colors, 'dark-blue');
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
.dropdown-toggle-hide-after {
|
||||
&::after {
|
||||
display: none;
|
||||
|
@ -108,6 +146,7 @@ body {
|
|||
.table .thead-light {
|
||||
a, th {
|
||||
color: map-get($theme-colors, 'dark-blue');
|
||||
background: lighten(map-get($theme-colors, 'dark-blue'), 80%);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -173,7 +212,7 @@ tr.table-primary-light {
|
|||
|
||||
|
||||
.sidebar {
|
||||
width: 260px;
|
||||
width: $sidebar-width;
|
||||
display: inline-block;
|
||||
|
||||
.sidebar-toggler {
|
||||
|
@ -253,8 +292,8 @@ tr.table-primary-light {
|
|||
|
||||
.body {
|
||||
padding-top: 60px;
|
||||
width: calc(100% - 260px);
|
||||
margin-left: 260px;
|
||||
width: calc(100% - $sidebar-width);
|
||||
margin-left: $sidebar-width;
|
||||
display: inline-block;
|
||||
|
||||
.nav {
|
||||
|
@ -400,6 +439,21 @@ th {
|
|||
margin-right: 4px;
|
||||
}
|
||||
|
||||
.form-color {
|
||||
display: inline-block;
|
||||
line-height: 0;
|
||||
border-radius: 25%;
|
||||
|
||||
input {
|
||||
padding: 0;
|
||||
border: 0;
|
||||
height: auto;
|
||||
width: 30px;
|
||||
aspect-ratio: 1/1;
|
||||
display: inline-block;
|
||||
}
|
||||
}
|
||||
|
||||
#form-main {
|
||||
> .tab-content {
|
||||
@media screen and (min-width: 500px) {
|
||||
|
@ -565,7 +619,11 @@ fieldset.form-group {
|
|||
|
||||
&-filter {
|
||||
padding-right: 20px;
|
||||
padding-bottom: 20px;
|
||||
padding-bottom: 15px;
|
||||
|
||||
.pagination {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 769px) {
|
||||
padding-right: 10px;
|
||||
|
@ -596,8 +654,20 @@ fieldset.form-group {
|
|||
}
|
||||
}
|
||||
|
||||
.table .crud-batch-column {
|
||||
width: 1%;
|
||||
.table {
|
||||
.crud-batch-column {
|
||||
width: 1%;
|
||||
}
|
||||
|
||||
.crud-action-column {
|
||||
text-align: right;
|
||||
white-space: nowrap;
|
||||
width: 1px;
|
||||
}
|
||||
}
|
||||
|
||||
.no-wrap {
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
form {
|
||||
|
@ -655,6 +725,16 @@ form {
|
|||
}
|
||||
}
|
||||
|
||||
label.required::after {
|
||||
content: '*';
|
||||
margin-left: 3px;
|
||||
color: #b41215;
|
||||
}
|
||||
|
||||
.invalid-feedback {
|
||||
margin-top: -3px;
|
||||
}
|
||||
|
||||
.gjs-editor-cont {
|
||||
border-radius: 10px;
|
||||
overflow: hidden !important;
|
||||
|
@ -664,6 +744,18 @@ form {
|
|||
background: map-get($theme-colors, 'dark-blue');
|
||||
}
|
||||
|
||||
.tox.tox-silver-sink.tox-tinymce-aux {
|
||||
z-index: 3000 !important;
|
||||
.tox {
|
||||
&.tox-silver-sink.tox-tinymce-aux {
|
||||
z-index: 3000 !important;
|
||||
}
|
||||
|
||||
&.tox-tinymce {
|
||||
border-color: $input-border-color;
|
||||
border-radius: 5px;
|
||||
}
|
||||
}
|
||||
|
||||
.field-boolean {
|
||||
color: #49555b;
|
||||
font-size: 20px;
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import '../../../../../../../../assets/css/admin.scss';
|
||||
|
||||
require('../../../../../../../../node_modules/bootstrap/dist/js/bootstrap.min.js')
|
||||
require('./modules/sidebar.js')()
|
||||
require('./modules/table-fixed.js')()
|
||||
require('./modules/form-confirm.js')()
|
||||
require('./modules/form-file.js')()
|
||||
|
@ -27,5 +28,4 @@ require('./modules/file-manager.js')()
|
|||
require('./modules/file-picker.js')()
|
||||
require('./modules/analytics.js')()
|
||||
require('./modules/page.js')()
|
||||
require('./modules/sidebar.js')()
|
||||
require('./modules/node.js')()
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
<select v-model="sort" class="form-control form-control-sm d-inline w-auto ml-1">
|
||||
<option value="name">Name</option>
|
||||
<option value="updated_at">Date</option>
|
||||
<option value="type">Type</option>
|
||||
</select>
|
||||
<select v-model="sortDirection" class="form-control form-control-sm d-inline w-auto ml-1">
|
||||
<option value="asc">ASC</option>
|
||||
|
@ -384,7 +385,7 @@ export default {
|
|||
|
||||
$(events).each((k, event) => {
|
||||
body.on(event + '.success', () => {
|
||||
$('div[id^=modal-container]').modal('hide')
|
||||
$('div[id^=modal-container-]').modal('hide')
|
||||
that.refresh()
|
||||
})
|
||||
})
|
||||
|
@ -392,6 +393,10 @@ export default {
|
|||
body.on('file_manager.info.update.success', () => {
|
||||
$('*[data-modal="' + that.modalUrl + '"]').click()
|
||||
})
|
||||
|
||||
body.on('file_manager.info.directory.request_open', () => {
|
||||
$('*[data-modal="' + that.modalUrl + '"]').click()
|
||||
})
|
||||
},
|
||||
watch: {
|
||||
directory (directory) {
|
||||
|
|
|
@ -8,16 +8,28 @@ module.exports = () => {
|
|||
const form = $('#form-batch')
|
||||
|
||||
form.submit((e) => {
|
||||
e.preventDefault()
|
||||
const select = document.querySelector('#form-batch-action')
|
||||
const options = select.querySelectorAll('#form-batch-action option')
|
||||
let doPrevent = true
|
||||
|
||||
const route = form.attr('action')
|
||||
const datas = form.serialize()
|
||||
options.forEach((option) => {
|
||||
if (option.value === select.value && option.getAttribute('data-isglobal') === 'true') {
|
||||
doPrevent = false
|
||||
}
|
||||
})
|
||||
|
||||
form.addClass('is-loading')
|
||||
if (doPrevent) {
|
||||
e.preventDefault()
|
||||
|
||||
$.post(route, datas)
|
||||
.always(() => {
|
||||
document.location.reload()
|
||||
})
|
||||
const route = form.attr('action')
|
||||
const datas = form.serialize()
|
||||
|
||||
form.addClass('is-loading')
|
||||
|
||||
$.post(route, datas)
|
||||
.always(() => {
|
||||
document.location.reload()
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
const Choices = require('choices.js')
|
||||
const $ = require('jquery')
|
||||
|
||||
module.exports = function () {
|
||||
$('*[data-jschoice]').each(function (key, item) {
|
||||
return new Choices(item)
|
||||
module.exports = () => {
|
||||
document.querySelectorAll('*[data-jschoice]').forEach((item) => {
|
||||
return new Choices(item, {
|
||||
searchFields: ['label'],
|
||||
})
|
||||
})
|
||||
}
|
||||
|
|
|
@ -36,8 +36,9 @@ const fileManagerBrowser = function (callback) {
|
|||
|
||||
const clickCallback = (e) => {
|
||||
callback($(e.target).attr('data-value'), {})
|
||||
$('div[id^="modal-container-"]').modal('hide')
|
||||
container.modal('hide')
|
||||
$('#fm-modal').next('.modal-backdrop').remove()
|
||||
$('#fm-modal').next('div[id^="modal-container-"]').modal('hide')
|
||||
$('#fm-modal').modal('hide')
|
||||
|
||||
$('body').off('click', '#file-manager-insert', clickCallback)
|
||||
}
|
||||
|
|
|
@ -1,9 +1,34 @@
|
|||
const $ = require('jquery')
|
||||
|
||||
const SidebarOpener = () => {
|
||||
$('.sidebar-toggler .btn').click(() => {
|
||||
$('.sidebar').toggleClass('is-open')
|
||||
const Sidebar = () => {
|
||||
const menu = document.querySelector('.sidebar')
|
||||
|
||||
if (!menu) {
|
||||
return
|
||||
}
|
||||
|
||||
const stickyMenu = menu.querySelector('.sidebar-sticky')
|
||||
const items = stickyMenu.querySelectorAll('a.nav-link')
|
||||
const currentItem = menu.querySelector('.nav-link.active')
|
||||
|
||||
items.forEach((item) => {
|
||||
item.addEventListener('click', () => {
|
||||
localStorage.setItem('sidebar-item-top', stickyMenu.scrollTop)
|
||||
})
|
||||
})
|
||||
|
||||
const toggler = menu.querySelector('.sidebar-toggler .btn')
|
||||
|
||||
toggler.addEventListener('click', () => {
|
||||
menu.classList.toggle('is-open')
|
||||
})
|
||||
|
||||
if (currentItem) {
|
||||
stickyMenu.scrollTo({
|
||||
top: Math.min(currentItem.offsetTop, localStorage.getItem('sidebar-item-top') ?? 0),
|
||||
behavior: 'smooth'
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = SidebarOpener
|
||||
module.exports = Sidebar
|
||||
|
|
|
@ -36,7 +36,7 @@ const fileManagerBrowser = function (callback) {
|
|||
|
||||
const clickCallback = (e) => {
|
||||
callback($(e.target).attr('data-value'), {})
|
||||
$('div[id^="modal-container"]').modal('hide')
|
||||
$('div[id^="modal-container-"]').modal('hide')
|
||||
container.modal('hide')
|
||||
|
||||
$('body').off('click', '#file-manager-insert', clickCallback)
|
||||
|
@ -53,7 +53,7 @@ const fileManagerBrowser = function (callback) {
|
|||
})
|
||||
}
|
||||
|
||||
if (typeof window.tinymce !== 'undefined') {
|
||||
const createTinymceConfig = function () {
|
||||
window.tinymce.murph = window.tinymce.murph || {}
|
||||
window.tinymce.murph.selector = window.tinymce.murph.selector || '*[data-tinymce]'
|
||||
window.tinymce.murph.configurationBase = window.tinymce.murph.configurationBase || {
|
||||
|
@ -80,6 +80,7 @@ if (typeof window.tinymce !== 'undefined') {
|
|||
}
|
||||
|
||||
window.tinymce.murph.modes = window.tinymce.murph.modes || {}
|
||||
window.tinymceModes = window.tinymceModes || {}
|
||||
|
||||
window.tinymce.murph.modes.default = window.tinymce.murph.modes.default || {
|
||||
plugins: 'print preview importcss searchreplace visualblocks visualchars fullscreen template table charmap hr pagebreak nonbreaking toc insertdatetime advlist lists wordcount textpattern noneditable help charmap quickbars link image code autoresize',
|
||||
|
@ -95,6 +96,11 @@ if (typeof window.tinymce !== 'undefined') {
|
|||
toolbar: 'undo redo | bold italic underline'
|
||||
}
|
||||
|
||||
window.tinymce.murph.modes = {
|
||||
...window.tinymce.murph.modes,
|
||||
...window.tinymceModes
|
||||
}
|
||||
|
||||
tinymce.addI18n('fr_FR', {
|
||||
Redo: 'R\u00e9tablir',
|
||||
Undo: 'Annuler',
|
||||
|
@ -612,15 +618,20 @@ const doInitEditor = () => {
|
|||
}
|
||||
|
||||
module.exports = function () {
|
||||
if (typeof tinymce === 'undefined') {
|
||||
return
|
||||
}
|
||||
|
||||
const observer = new MutationObserver(doInitEditor)
|
||||
const config = { attributes: false, childList: true, subtree: true }
|
||||
observer.observe(document.querySelector('body'), config)
|
||||
|
||||
$(() => {
|
||||
createTinymceConfig()
|
||||
doInitEditor()
|
||||
|
||||
const observer = new MutationObserver(doInitEditor)
|
||||
const config = { attributes: false, childList: true, subtree: true }
|
||||
observer.observe(document.querySelector('body'), config)
|
||||
|
||||
$('body').on('hidden.bs.modal', '.modal', (e) => {
|
||||
if (!$('.tox-dialog').length) {
|
||||
$(e.target).find('.tox-tinymce').each(() => {
|
||||
window.tinymce.remove($(this).prev().attr('id'))
|
||||
})
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
|
|
@ -1,74 +1,79 @@
|
|||
<?= "<?php\n" ?>
|
||||
<?php echo "<?php\n"; ?>
|
||||
|
||||
namespace <?= $namespace; ?>;
|
||||
namespace <?php echo $namespace; ?>;
|
||||
|
||||
use App\Core\Controller\Admin\Crud\CrudController;
|
||||
use App\Core\Crud\CrudConfiguration;
|
||||
use App\Core\Crud\Field;
|
||||
use App\Core\Entity\EntityInterface;
|
||||
use App\Core\Manager\EntityManager;
|
||||
use <?= $entity ?> as Entity;
|
||||
use <?= $factory ?> as Factory;
|
||||
use <?= $form ?> as Type;
|
||||
use <?= $repository_query ?> as RepositoryQuery;
|
||||
use <?php echo $entity; ?> as Entity;
|
||||
use <?php echo $factory; ?> as Factory;
|
||||
use <?php echo $form; ?> as Type;
|
||||
use <?php echo $repository_query; ?> as RepositoryQuery;
|
||||
use Sensio\Bundle\FrameworkExtraBundle\Configuration\IsGranted;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\HttpFoundation\Session\Session;
|
||||
use Symfony\Component\Routing\Annotation\Route;
|
||||
|
||||
class <?= $class_name; ?> extends CrudController
|
||||
class <?php echo $class_name; ?> extends CrudController
|
||||
{
|
||||
#[Route(path: '/admin/user/edit/{entity}', name: 'admin_user_edit', methods: ['GET', 'POST'])]
|
||||
protected ?CrudConfiguration $configuration = null;
|
||||
|
||||
#[Route(path: "/admin/<?= $route; ?>/{page}", name: "admin_<?= $route; ?>_index", methods: ['GET'], requirements: ['page' => '\d+'])]
|
||||
#[Route(path: '/admin/<?php echo $route; ?>/{page}', name: 'admin_<?php echo $route; ?>_index', methods: ['GET'], requirements: ['page' => '\d+'])]
|
||||
public function index(RepositoryQuery $query, Request $request, Session $session, int $page = 1): Response
|
||||
{
|
||||
return $this->doIndex($page, $query, $request, $session);
|
||||
}
|
||||
|
||||
#[Route(path: "/admin/<?= $route; ?>/new", name: "admin_<?= $route; ?>_new", methods: ['GET', 'POST'])]
|
||||
#[Route(path: '/admin/<?php echo $route; ?>/new', name: 'admin_<?php echo $route; ?>_new', methods: ['GET', 'POST'])]
|
||||
public function new(Factory $factory, EntityManager $entityManager, Request $request): Response
|
||||
{
|
||||
return $this->doNew($factory->create(), $entityManager, $request);
|
||||
}
|
||||
|
||||
#[Route(path: "/admin/<?= $route; ?>/show/{entity}", name: "admin_<?= $route; ?>_show", methods: ['GET'])]
|
||||
#[Route(path: '/admin/<?php echo $route; ?>/show/{entity}', name: 'admin_<?php echo $route; ?>_show', methods: ['GET'])]
|
||||
#[IsGranted('show', 'entity')]
|
||||
public function show(Entity $entity): Response
|
||||
{
|
||||
return $this->doShow($entity);
|
||||
}
|
||||
|
||||
#[Route(path: "/admin/<?= $route; ?>/filter", name: "admin_<?= $route; ?>_filter", methods: ['GET'])]
|
||||
#[Route(path: '/admin/<?php echo $route; ?>/filter', name: 'admin_<?php echo $route; ?>_filter', methods: ['GET'])]
|
||||
public function filter(Session $session): Response
|
||||
{
|
||||
return $this->doFilter($session);
|
||||
}
|
||||
|
||||
#[Route(path: "/admin/<?= $route; ?>/edit/{entity}", name: "admin_<?= $route; ?>_edit", methods: ['GET', 'POST'])]
|
||||
#[Route(path: '/admin/<?php echo $route; ?>/edit/{entity}', name: 'admin_<?php echo $route; ?>_edit', methods: ['GET', 'POST'])]
|
||||
#[IsGranted('edit', 'entity')]
|
||||
public function edit(Entity $entity, EntityManager $entityManager, Request $request): Response
|
||||
{
|
||||
return $this->doEdit($entity, $entityManager, $request);
|
||||
}
|
||||
|
||||
#[Route(path: "/admin/<?= $route; ?>/inline_edit/{entity}/{context}/{label}", name: 'admin_<?= $route; ?>_inline_edit', methods: ['GET', 'POST'])]
|
||||
#[Route(path: '/admin/<?php echo $route; ?>/inline_edit/{entity}/{context}/{label}', name: 'admin_<?php echo $route; ?>_inline_edit', methods: ['GET', 'POST'])]
|
||||
#[IsGranted('edit', 'entity')]
|
||||
public function inlineEdit(string $context, string $label, Entity $entity, EntityManager $entityManager, Request $request): Response
|
||||
{
|
||||
return $this->doInlineEdit($context, $label, $entity, $entityManager, $request);
|
||||
}
|
||||
|
||||
#[Route(path: "/admin/<?= $route; ?>/sort/{page}", name: "admin_<?= $route; ?>_sort", methods: ['POST'], requirements: ['page' => '\d+'])]
|
||||
#[Route(path: '/admin/<?php echo $route; ?>/sort/{page}', name: 'admin_<?php echo $route; ?>_sort', methods: ['POST'], requirements: ['page' => '\d+'])]
|
||||
public function sort(RepositoryQuery $query, EntityManager $entityManager, Request $request, Session $session, int $page = 1): Response
|
||||
{
|
||||
return $this->doSort($page, $query, $entityManager, $request, $session);
|
||||
}
|
||||
|
||||
#[Route(path: "/admin/<?= $route; ?>/batch/{page}", name: "admin_<?= $route; ?>_batch", methods: ['POST'], requirements: ['page' => '\d+'])]
|
||||
#[Route(path: '/admin/<?php echo $route; ?>/batch/{page}', name: 'admin_<?php echo $route; ?>_batch', methods: ['POST'], requirements: ['page' => '\d+'])]
|
||||
public function batch(RepositoryQuery $query, EntityManager $entityManager, Request $request, Session $session, int $page = 1): Response
|
||||
{
|
||||
return $this->doBatch($page, $query, $entityManager, $request, $session);
|
||||
}
|
||||
|
||||
#[Route(path: "/admin/<?= $route; ?>/delete/{entity}", name: "admin_<?= $route; ?>_delete", methods: ['DELETE', 'POST'])]
|
||||
#[Route(path: '/admin/<?php echo $route; ?>/delete/{entity}', name: 'admin_<?php echo $route; ?>_delete', methods: ['DELETE', 'POST'])]
|
||||
#[IsGranted('delete', 'entity')]
|
||||
public function delete(Entity $entity, EntityManager $entityManager, Request $request): Response
|
||||
{
|
||||
return $this->doDelete($entity, $entityManager, $request);
|
||||
|
@ -76,24 +81,32 @@ class <?= $class_name; ?> extends CrudController
|
|||
|
||||
protected function getConfiguration(): CrudConfiguration
|
||||
{
|
||||
return CrudConfiguration::create()
|
||||
->setPageTitle('index', 'List of <?= $entity; ?>')
|
||||
if ($this->configuration) {
|
||||
return $this->configuration;
|
||||
}
|
||||
|
||||
return $this->configuration = CrudConfiguration::create()
|
||||
->setPageTitle('index', 'List of <?php echo $entity; ?>')
|
||||
->setPageTitle('edit', 'Edition of {id}')
|
||||
->setPageTitle('new', 'New <?= $entity; ?>')
|
||||
->setPageTitle('new', 'New <?php echo $entity; ?>')
|
||||
->setPageTitle('show', 'View of {id}')
|
||||
|
||||
->setPageRoute('index', 'admin_<?= $route; ?>_index')
|
||||
->setPageRoute('new', 'admin_<?= $route; ?>_new')
|
||||
->setPageRoute('edit', 'admin_<?= $route; ?>_edit')
|
||||
->setPageRoute('inline_edit', 'admin_<?= $route; ?>_inline_edit')
|
||||
->setPageRoute('show', 'admin_<?= $route; ?>_show')
|
||||
->setPageRoute('sort', 'admin_<?= $route; ?>_sort')
|
||||
->setPageRoute('batch', 'admin_<?= $route; ?>_batch')
|
||||
->setPageRoute('delete', 'admin_<?= $route; ?>_delete')
|
||||
->setPageRoute('filter', 'admin_<?= $route; ?>_filter')
|
||||
->setPageRoute('index', 'admin_<?php echo $route; ?>_index')
|
||||
->setPageRoute('new', 'admin_<?php echo $route; ?>_new')
|
||||
->setPageRoute('edit', 'admin_<?php echo $route; ?>_edit')
|
||||
->setPageRoute('inline_edit', 'admin_<?php echo $route; ?>_inline_edit')
|
||||
->setPageRoute('show', 'admin_<?php echo $route; ?>_show')
|
||||
->setPageRoute('sort', 'admin_<?php echo $route; ?>_sort')
|
||||
->setPageRoute('batch', 'admin_<?php echo $route; ?>_batch')
|
||||
->setPageRoute('delete', 'admin_<?php echo $route; ?>_delete')
|
||||
->setPageRoute('filter', 'admin_<?php echo $route; ?>_filter')
|
||||
|
||||
->setForm('edit', Type::class, [])
|
||||
->setForm('edit', Type::class)
|
||||
->setForm('new', Type::class)
|
||||
|
||||
->setView('form', 'admin/<?php echo $route; ?>_admin/_form.html.twig')
|
||||
->setView('show_entity', 'admin/<?php echo $route; ?>_admin/_show.html.twig')
|
||||
|
||||
// ->setForm('filter', Type::class)
|
||||
|
||||
// ->setMaxPerPage('index', 20)
|
||||
|
@ -136,6 +149,6 @@ class <?= $class_name; ?> extends CrudController
|
|||
|
||||
protected function getSection(): string
|
||||
{
|
||||
return '<?= $route; ?>';
|
||||
return '<?php echo $route; ?>';
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
<?= "<?php\n" ?>
|
||||
<?php echo "<?php\n"; ?>
|
||||
|
||||
namespace <?= $namespace; ?>;
|
||||
namespace <?php echo $namespace; ?>;
|
||||
|
||||
use App\Core\Factory\FactoryInterface;
|
||||
use <?= $entity ?> as Entity;
|
||||
use <?php echo $entity; ?> as Entity;
|
||||
|
||||
class <?= $class_name; ?> implements FactoryInterface
|
||||
class <?php echo $class_name; ?> implements FactoryInterface
|
||||
{
|
||||
public function create(): Entity
|
||||
{
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<?= "<?php\n" ?>
|
||||
<?php echo "<?php\n"; ?>
|
||||
|
||||
namespace <?= $namespace; ?>;
|
||||
namespace <?php echo $namespace; ?>;
|
||||
|
||||
use App\Core\Entity\Site\Page\Page;
|
||||
use App\Core\Entity\Site\Page as BlockEntity;
|
||||
|
@ -9,28 +9,28 @@ use Doctrine\ORM\Mapping as ORM;
|
|||
use Symfony\Component\Form\FormBuilderInterface;
|
||||
|
||||
#[ORM\Entity]
|
||||
class <?= $class_name; ?> extends Page
|
||||
class <?php echo $class_name; ?> extends Page
|
||||
{
|
||||
public function buildForm(FormBuilderInterface $builder, array $options)
|
||||
{
|
||||
<?php if (count($blocks)): ?> $builder
|
||||
<?php foreach ($blocks as $block): ?>
|
||||
->add('<?= $block['name'] ?>', <?= $block['type'] ?>)
|
||||
<?php endforeach; ?>
|
||||
<?php if (count($blocks)) { ?> $builder
|
||||
<?php foreach ($blocks as $block) { ?>
|
||||
->add('<?php echo $block['name']; ?>', <?php echo $block['type']; ?>)
|
||||
<?php } ?>
|
||||
;
|
||||
<?php endif; ?>
|
||||
<?php } ?>
|
||||
}
|
||||
|
||||
<?php foreach ($blocks as $block): ?>
|
||||
public function set<?= $block['camelCase'] ?>(BlockEntity\Block $block)
|
||||
<?php foreach ($blocks as $block) { ?>
|
||||
public function set<?php echo $block['camelCase']; ?>(BlockEntity\Block $block)
|
||||
{
|
||||
return $this->setBlock($block);
|
||||
}
|
||||
|
||||
public function get<?= $block['camelCase'] ?>()
|
||||
public function get<?php echo $block['camelCase']; ?>()
|
||||
{
|
||||
return $this->getBlock('<?= $block['name'] ?>'<?php if ($block['class']): ?>, <?= $block['class'] ?><?php endif; ?>);
|
||||
return $this->getBlock('<?php echo $block['name']; ?>'<?php if ($block['class']) { ?>, <?php echo $block['class']; ?><?php } ?>);
|
||||
}
|
||||
|
||||
<?php endforeach; ?>
|
||||
<?php } ?>
|
||||
}
|
||||
|
|
|
@ -1,15 +1,15 @@
|
|||
<?= "<?php\n" ?>
|
||||
<?php echo "<?php\n"; ?>
|
||||
|
||||
namespace <?= $namespace; ?>;
|
||||
namespace <?php echo $namespace; ?>;
|
||||
|
||||
use App\Core\Repository\RepositoryQuery;
|
||||
use Knp\Component\Pager\PaginatorInterface;
|
||||
use <?= $repository; ?> as Repository;
|
||||
use <?php echo $repository; ?> as Repository;
|
||||
|
||||
class <?= $class_name; ?> extends RepositoryQuery
|
||||
class <?php echo $class_name; ?> extends RepositoryQuery
|
||||
{
|
||||
public function __construct(Repository $repository, PaginatorInterface $paginator)
|
||||
{
|
||||
parent::__construct($repository, '<?= $id; ?>', $paginator);
|
||||
parent::__construct($repository, '<?php echo $id; ?>', $paginator);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -64,7 +64,7 @@
|
|||
"Display name": "Nom d'affichage"
|
||||
"Administrator": "Administrateur⋅trice"
|
||||
"Writer": "Rédacteur⋅trice"
|
||||
"Reference": "Élement de référence"
|
||||
"Reference": "Référence"
|
||||
"My account": "Mon compte"
|
||||
"Logout": "Déconnexion"
|
||||
"Dashboard": "Tableau de bord"
|
||||
|
@ -144,7 +144,7 @@
|
|||
"Username or e-mail": "Identifiant ou e-mail"
|
||||
"Submit": "Soumettre"
|
||||
"If the information submitted corresponds to a user account, you will receive an e-mail with the link to initiate the password change procedure.": "Si les informations soumises correspondent à un compte utilisateur, vous allez recevoir un e-mail avec en lien pour enclancher la procédure de changement de mot de passe."
|
||||
"Enter your account username or email address. An e-mail will be sent to you to initiate the password change procedure. ": "Saisissez le nom d'utilisateur ou l'adresse e-mail de votre compte. Un e-mail vous sera envoyé pour enclancher la procédure de changement de mot de passe."
|
||||
"Enter your account username or email address. An e-mail will be sent to you to initiate the password change procedure.": "Saisissez le nom d'utilisateur ou l'adresse e-mail de votre compte. Un e-mail vous sera envoyé pour enclancher la procédure de changement de mot de passe."
|
||||
"Show the login page": "Afficher la page de connexion"
|
||||
"A password reset request has been made. If you are the source of this request, click on the link below or copy and paste the address if the link does not work.": "Une demande de réinitialisation de mot de passe a été réalisée. Si vous êtes à l'origine de cette demande, cliquer sur le lien ci-dessous ou copier et coller l'adresse si le lien ne fonctionne pas."
|
||||
"Edit the routing": "Éditez le routage"
|
||||
|
@ -223,3 +223,4 @@
|
|||
"At least one role": "Au moins un rôle"
|
||||
"All roles": "Tous les rôles"
|
||||
"Enable A/B Testing": "Activer le test A/B"
|
||||
"Color": "Couleur"
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
{% import _self as macros %}
|
||||
|
||||
{% block title %}{{ 'My account'|trans }} - {{ parent() }}{% endblock %}
|
||||
{% block title %}{{ 'My account'|trans }} {{ parent() ? ('- ' ~ parent()) : '' }}{% endblock %}
|
||||
|
||||
{% block body %}
|
||||
<div class="bg-light">
|
||||
|
@ -12,7 +12,7 @@
|
|||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-6">
|
||||
<div class="col-12 col-md-6">
|
||||
<form action="{{ path('admin_account_password') }}" method="post">
|
||||
<div class="tab-content">
|
||||
<div class="tab-pane active">
|
||||
|
@ -102,7 +102,7 @@
|
|||
</form>
|
||||
</div>
|
||||
|
||||
<div class="col-6">
|
||||
<div class="col-12 col-md-6">
|
||||
<form action="{{ path('admin_account_2fa') }}" method="post">
|
||||
<div class="tab-content">
|
||||
<div class="tab-pane active">
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<div class="row">
|
||||
<div class="col-md-12 p-3">
|
||||
{% for item in entity_to_array(entity) %}
|
||||
{% for item in entity_to_array(entity, false, ['id']) %}
|
||||
<div class="font-weight-bold">{{ item.name|trans }}</div>
|
||||
<div class="mb-3">{{ item.value }}</div>
|
||||
{% endfor %}
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
{% block body_class %}has-form{% endblock %}
|
||||
|
||||
{% block title %}{{ configuration.pageTitle(context)|trans|build_string(entity) }} - {{ parent() }}{% endblock %}
|
||||
{% block title %}{{ configuration.pageTitle(context)|trans|build_string(entity) }} {{ parent() ? ('- ' ~ parent()) : '' }}{% endblock %}
|
||||
|
||||
{% block body %}
|
||||
{% block header %}
|
||||
|
|
22
src/core/Resources/views/admin/crud/field/boolean.html.twig
Normal file
22
src/core/Resources/views/admin/crud/field/boolean.html.twig
Normal file
|
@ -0,0 +1,22 @@
|
|||
{%- block value -%}
|
||||
{% set value = value|default(options.default_value) %}
|
||||
<span class="field-boolean">
|
||||
{% if options.display == 'checkbox' %}
|
||||
{% block checkbox %}
|
||||
<span class="fa {{ value ? options.checkbox_class_when_true : options.checkbox_class_when_false }}"></span>
|
||||
{% endblock %}
|
||||
{% elseif options.display == 'toggle' %}
|
||||
{% block toggle %}
|
||||
{% if value %}
|
||||
<span class="rounded-pill pl-3 pr-1 text-white {{ options.toggle_class_when_true }}">
|
||||
<span class="fa fa-circle"></span>
|
||||
</span>
|
||||
{% else %}
|
||||
<span class="rounded-pill pr-3 pl-1 text-white {{ options.toggle_class_when_false }}">
|
||||
<span class="fa fa-circle"></span>
|
||||
</span>
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
{% endif %}
|
||||
</span>
|
||||
{%- endblock -%}
|
|
@ -2,7 +2,7 @@
|
|||
{%- if value -%}
|
||||
<span class="btn btn-sm btn-light">
|
||||
<span class="fa fa-calendar-alt text-black-50 mr-2"></span>
|
||||
{{- value|date(options.format) -}}
|
||||
{{- value|default(options.default_value)|date(options.format) -}}
|
||||
</span>
|
||||
{%- endif -%}
|
||||
{%- endblock -%}
|
||||
|
|
|
@ -1,3 +1,7 @@
|
|||
{%- block value -%}
|
||||
<img {% for k, v in options.image_attr %}{{ k }}="{{ v }}" {% endfor %} src="{{ asset(value) }}">
|
||||
{% set value = value|default(options.default_value) %}
|
||||
|
||||
{% if value %}
|
||||
<img {% for k, v in options.image_attr %}{{ k }}="{{ v }}" {% endfor %} src="{{ asset(value) }}">
|
||||
{% endif %}
|
||||
{%- endblock -%}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
{%- block value -%}
|
||||
{%- if options.raw -%}
|
||||
{{- value|raw -}}
|
||||
{{- value|default(options.default_value)|raw -}}
|
||||
{%- else -%}
|
||||
{{- value|trans -}}
|
||||
{{- value|default(options.default_value)|trans -}}
|
||||
{%- endif -%}
|
||||
{%- endblock -%}
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
{% extends '@Core/admin/layout.html.twig' %}
|
||||
|
||||
{% set context = context ?? 'index' %}
|
||||
{% set pager_render = pager is defined ? knp_pagination_render(pager) : null %}
|
||||
|
||||
{% block title %}{{ configuration.pageTitle(context)|trans }} - {{ parent() }}{% endblock %}
|
||||
{% block title %}{{ configuration.pageTitle(context)|trans }} {{ parent() ? ('- ' ~ parent()) : '' }}{% endblock %}
|
||||
|
||||
{% block body %}
|
||||
{% block header %}
|
||||
|
@ -67,16 +68,17 @@
|
|||
<div class="row crud-header-filter">
|
||||
<div class="col-auto ml-auto {% if pager.getPaginationData.pageCount > 1 %}mr-3{% endif %}">
|
||||
<button data-modal="{{ path(configuration.pageRoute('filter'), configuration.pageRouteParams('filter')) }}" class="btn btn-sm btn-secondary">
|
||||
<span class="fa fa-search mr-1"></span>
|
||||
{{ 'Filter'|trans }} {% if not filters.isEmpty %}({{ 'yes'|trans }}){% endif %}
|
||||
</button>
|
||||
</div>
|
||||
<div class="col-auto">
|
||||
{{ knp_pagination_render(pager) }}
|
||||
{{ pager_render|raw }}
|
||||
</div>
|
||||
</div>
|
||||
{% else %}
|
||||
<div class="crud-header-filter">
|
||||
{{ knp_pagination_render(pager) }}
|
||||
{{ pager_render|raw }}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
@ -85,6 +87,7 @@
|
|||
|
||||
{% block list %}
|
||||
{% set isSortable = configuration.isSortableCollection(context) %}
|
||||
{% set colspan = configuration.fields(context)|length + 1 + (configuration.hasBatchAction(context) ? 1 : 0) %}
|
||||
|
||||
<div class="table-responsive">
|
||||
<table class="table">
|
||||
|
@ -129,10 +132,13 @@
|
|||
|
||||
<a href="{{ url }}">
|
||||
{% if icon is defined %}
|
||||
<span class="{{ icon }}"></span>
|
||||
<span class="no-wrap">
|
||||
<span class="{{ icon }}"></span>
|
||||
{{ label|trans }}
|
||||
</span>
|
||||
{% else %}
|
||||
{{ label|trans }}
|
||||
{% endif %}
|
||||
|
||||
{{ label|trans }}
|
||||
</a>
|
||||
{% else %}
|
||||
{{ label|trans }}
|
||||
|
@ -144,7 +150,7 @@
|
|||
{% endblock %}
|
||||
{% endfor %}
|
||||
{% if configuration.showActions %}
|
||||
<th class="crud-action-column col-2 miw-100 text-right">
|
||||
<th class="crud-action-column">
|
||||
{{ 'Actions'|trans }}
|
||||
</th>
|
||||
{% endif %}
|
||||
|
@ -204,7 +210,7 @@
|
|||
entity: item.id,
|
||||
context: context,
|
||||
label: label,
|
||||
redirectTo: app.request.uri,
|
||||
redirectTo: app.request.pathInfo,
|
||||
}|merge(configuration.pagerouteparams('inline_edit'))) }}" data-modal-create>
|
||||
{{ render_field(item, config, configuration.defaultlocale) }}
|
||||
</a>
|
||||
|
@ -223,33 +229,41 @@
|
|||
{% endfor %}
|
||||
|
||||
{% if configuration.showActions %}
|
||||
<td class="crud-action-column col-2 miw-200 text-right">
|
||||
{% block list_item_actions_before %}{% endblock %}
|
||||
<td class="crud-action-column">
|
||||
{% block list_item_actions %}
|
||||
{% block list_item_actions_before %}{% endblock %}
|
||||
|
||||
{% if configuration.action(context, 'show', true, [item]) %}
|
||||
<a href="{{ path(configuration.pageRoute('show'), {entity: item.id}|merge(configuration.pageRouteParams('show'))) }}" class="btn btn-sm btn-secondary mr-1">
|
||||
<span class="fa fa-eye"></span>
|
||||
</a>
|
||||
{% endif %}
|
||||
{% block list_item_action_show %}
|
||||
{% if configuration.action(context, 'show', true, [item]) %}
|
||||
<a href="{{ path(configuration.pageRoute('show'), {entity: item.id}|merge(configuration.pageRouteParams('show'))) }}" class="btn btn-sm btn-secondary mr-1">
|
||||
<span class="fa fa-eye"></span>
|
||||
</a>
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
||||
{% if configuration.action(context, 'edit', true, [item]) %}
|
||||
<a href="{{ path(configuration.pageRoute('edit'), {entity: item.id}|merge(configuration.pageRouteParams('edit'))) }}" class="btn btn-sm btn-primary mr-1">
|
||||
<span class="fa fa-edit"></span>
|
||||
</a>
|
||||
{% endif %}
|
||||
{% block list_item_action_edit %}
|
||||
{% if configuration.action(context, 'edit', true, [item]) %}
|
||||
<a href="{{ path(configuration.pageRoute('edit'), {entity: item.id}|merge(configuration.pageRouteParams('edit'))) }}" class="btn btn-sm btn-primary mr-1">
|
||||
<span class="fa fa-edit"></span>
|
||||
</a>
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
||||
{% if configuration.action(context, 'delete', true, [item]) %}
|
||||
<button type="submit" form="form-delete-{{ item.id }}" class="btn btn-sm btn-danger">
|
||||
<span class="fa fa-trash"></span>
|
||||
</button>
|
||||
{% block list_item_action_delete %}
|
||||
{% if configuration.action(context, 'delete', true, [item]) %}
|
||||
<button type="submit" form="form-delete-{{ item.id }}" class="btn btn-sm btn-danger">
|
||||
<span class="fa fa-trash"></span>
|
||||
</button>
|
||||
|
||||
<form method="post" action="{{ path(configuration.pageRoute('delete'), {entity: item.id}|merge(configuration.pageRouteParams('delete'))) }}" id="form-delete-{{ item.id }}" data-form-confirm>
|
||||
<input type="hidden" name="_method" value="DELETE">
|
||||
<input type="hidden" name="_token" value="{{ csrf_token('delete' ~ item.id) }}">
|
||||
</form>
|
||||
{% endif %}
|
||||
<form method="post" action="{{ path(configuration.pageRoute('delete'), {entity: item.id}|merge(configuration.pageRouteParams('delete'))) }}" id="form-delete-{{ item.id }}" data-form-confirm>
|
||||
<input type="hidden" name="_method" value="DELETE">
|
||||
<input type="hidden" name="_token" value="{{ csrf_token('delete' ~ item.id) }}">
|
||||
</form>
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
||||
{% block list_item_actions_after %}{% endblock %}
|
||||
{% block list_item_actions_after %}{% endblock %}
|
||||
{% endblock %}
|
||||
</td>
|
||||
{% endif %}
|
||||
</tr>
|
||||
|
@ -273,17 +287,24 @@
|
|||
</div>
|
||||
{% endif %}
|
||||
|
||||
<div class="float-right mr-2">
|
||||
{{ pager_render|raw }}
|
||||
</div>
|
||||
|
||||
{% if configuration.hasBatchAction(context) %}
|
||||
<div class="mb-2">
|
||||
<form class="form-inline" action="{{ path(configuration.pageRoute('batch'), {page: pager.currentPageNumber}|merge(configuration.pageRouteParams('batch'))) }}" id="form-batch" method="POST">
|
||||
<form class="form-inline" action="{{ path(configuration.pageRoute('batch'), {
|
||||
page: pager.currentPageNumber,
|
||||
redirectTo: app.request.uri
|
||||
}|merge(configuration.pageRouteParams('batch'))) }}" id="form-batch" method="POST">
|
||||
<select class="form-control my-1 mr-sm-2" name="batch[target]">
|
||||
<option value="selection">{{ 'For selection'|trans }}</option>
|
||||
<option value="all">{{ 'For all items'|trans }}</option>
|
||||
</select>
|
||||
<select class="form-control my-1 mr-sm-2" name="batch[action]">
|
||||
<select class="form-control my-1 mr-sm-2" id="form-batch-action" name="batch[action]">
|
||||
<option value=""></option>
|
||||
{% for action, conf in configuration.batchActions(context) %}
|
||||
<option value="{{ action }}">
|
||||
<option value="{{ action }}" {% if conf.isGlobal %}data-isglobal="true"{% endif %}>
|
||||
{{ conf.label|trans }}
|
||||
</option>
|
||||
{% endfor %}
|
||||
|
@ -304,13 +325,8 @@
|
|||
{% endblock %}
|
||||
{% endif %}
|
||||
{% else %}
|
||||
{% set count = configuration.fields(context)|length + 1 %}
|
||||
{% if configuration.hasBatchAction(context) %}
|
||||
{% set count = count + 1 %}
|
||||
{% endif %}
|
||||
|
||||
<tr>
|
||||
<td class="col-12 text-center p-4 text-black-50" colspan="{{ count }}">
|
||||
<td class="col-12 text-center p-4 text-black-50" colspan="{{ colspan }}">
|
||||
<div class="display-1">
|
||||
<span class="fa fa-search"></span>
|
||||
</div>
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title">{{ label }}</h5>
|
||||
<h5 class="modal-title">{{ label|trans }}</h5>
|
||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<form action="{{ path(configuration.pageRoute('inline_edit'), {entity: entity.id, context: context, label: label, redirectTo, redirectTo}|merge(configuration.pageRouteParams('inline_edit'))) }}" id="form-entity-edit" method="POST">
|
||||
<form action="{{ path(configuration.pageRoute('inline_edit'), {entity: entity.id, context: context, label: label, redirectTo: redirectTo}|merge(configuration.pageRouteParams('inline_edit'))) }}" id="form-entity-edit" method="POST">
|
||||
{{ include('@Core/setting/setting_admin/_form.html.twig') }}
|
||||
</form>
|
||||
</div>
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue