new User()
вместо вашего кодаpublic function getUser($credentials, UserProviderInterface $userProvider)
{
return new User();
}
stateless: true
ContextListener manages the SecurityContext persistence through a session.
!$this->isGranted('IS_AUTHENTICATED_REMEMBERED');
$reflectionExtractor = new ReflectionExtractor();
$phpDocExtractor = new PhpDocExtractor();
$propertyTypeExtractor = new PropertyInfoExtractor([$reflectionExtractor], [$phpDocExtractor, $reflectionExtractor], [$phpDocExtractor], [$reflectionExtractor], [$reflectionExtractor]);
$normalizer = new ObjectNormalizer(null, null, null, $propertyTypeExtractor);
$arrayNormalizer = new ArrayDenormalizer();
$serializer = new Serializer([$arrayNormalizer, $normalizer]);
return $serializer->denormalize($array, ContragentDto::class);
firewalls:
main:
guard:
authenticators:
- App\Security\TokenAuthenticator
entry_point
- используется для начала процесса аутентификации. В вашем случае он не нужен, т.к. у вас api # config/services.yaml
services:
DependencyInterface: '@RealDependency'
# config/services_test.yaml
services:
DependencyInterface: '@FakeDependency'
// \App\Kernel
protected function initializeContainer()
{
if ($_ENV['APP_ENV'] === 'dev') {
$container = $this->buildContainer();
$container->setParameter('container.build_id', 'id');
$container->setParameter('container.build_hash', 'hash');
$container->set('kernel', $this);
$container->compile(true);
$this->container = $container;
} else {
parent::initializeContainer();
}
}
smart-core/accelerator-cache-bundle
, возможно другие бандлы тоже несовместимы с таким режимом.{{ render(controller(
AppBundle:Article:recentArticles',
{ 'max': 3 }
)) }}
{{ articles(3) }}
{{ app_version }}
app
, к примеру, тот же инстанс залогиненого пользователя{{ app.user.username }}
$form = $this->container->get('form.factory')
->createNamed(
'account_'. $account->getId(),
AccountType::class,
$account
)
;
public function indexAction(Request $request)
{
$accounts = $this
->getDoctrine()
->getRepository('AppBundle:Account')
->findActive();
$forms = [];
foreach ($accounts as $key => $account){
$form = $this->container->get('form.factory')->createNamed('account_'. $account->getId(), AccountType::class, $account);
// Не надо добавлять кнопки сабмита, их рекомендуется добавлять непосредственно в шаблоне обычным html
// $form->add('submit', SubmitType::class);
$form->handleRequest($request);
// Не надо инжектить форму в сущность, легче просто передать формы в шаблон
// $account->setForm($form);
// $account->setFormView($formView);
if($form->isSubmitted() && $form->isValid()){
// Объекты передаются по ссылке, нет смысла в получение $account повторно
// $data = $form->getData();
$this->addFlash('success', 'Saved');
$em = $this->getDoctrine()->getManager();
// Это актуально только для создания сущности, при редактировании - это не нужно
// $em->persist($data);
$em->flush();
return $this->redirectToRoute('account_list');
} else {
$forms[$account->getId()] = $form->createView();
}
}
return [
'forms' => $forms,
'accounts' => $accounts,
];
}
{# {{ form_row(account.formView) }} #}
{{ form_start(forms[account.id]) }}
{{ form_widget(forms[account.id]) }}
<button>Submit</button>
{{ form_end(forms[account.id]) }}
class TaskController
{
/**
* @var ProducerInterface
*/
private $producer;
public function __construct(ProducerInterface $producer)
{
$this->producer = $producer;
}
public function indexAction($name)
{
$this->producer->publish('test');
return new Response();
}
}
# services.yaml
services:
App\Controller\TaskController:
arguments:
- '@old_sound_rabbit_mq.task_producer'
# services.yaml
services:
OldSound\RabbitMqBundle\RabbitMq\ProducerInterface: '@old_sound_rabbit_mq.task_producer'
$query = $em->createQuery(
'SELECT NEW ArticleDTO(ar.title, ar.imagePath, ar.publishedAt, CONCAT(au.firstName, ' ', au.lastName))
FROM Article ar JOIN ar.author au');
$articles = $query->getResult(); // array of ArticleDTO
AnnotationClassLoader
, задачей которого преобразовывать аннотации в роуты. Абстрактный класс есть в компоненте, вам надо только определить метод configureRoute
. За основу можно взять код из фреймворкаnamespace App\Router;
use Symfony\Component\Routing\Loader\AnnotationClassLoader as BaseLoader;
use Symfony\Component\Routing\Route;
class AnnotationClassLoader extends BaseLoader
{
protected function configureRoute(Route $route, \ReflectionClass $class, \ReflectionMethod $method, $annot)
{
if ('__invoke' === $method->getName()) {
$route->setDefault('_controller', $class->getName());
} else {
$route->setDefault('_controller', $class->getName().'::'.$method->getName());
}
}
}
use App\Router\AnnotationClassLoader;
use Doctrine\Common\Annotations\AnnotationReader;
use Doctrine\Common\Annotations\AnnotationRegistry;
use Symfony\Component\Config\FileLocator;
use Symfony\Component\Config\Loader\DelegatingLoader;
use Symfony\Component\Config\Loader\LoaderResolver;
use Symfony\Component\Routing\Loader\AnnotationDirectoryLoader;
use Symfony\Component\Routing\Loader\AnnotationFileLoader;
use Symfony\Component\Routing\Router;
$autoloader = require_once __DIR__ . '/../vendor/autoload.php';
AnnotationRegistry::registerLoader(array($autoloader, 'loadClass'));
$reader = new AnnotationReader();
$annotationClassLoader = new AnnotationClassLoader($reader);
$fileLocator = new FileLocator([__DIR__]);
$loaderResolver = new LoaderResolver([
new AnnotationFileLoader($fileLocator, $annotationClassLoader),
new AnnotationDirectoryLoader($fileLocator, $annotationClassLoader),
]);
$loader = new DelegatingLoader($loaderResolver);
$router = new Router($loader, __DIR__ . '/../src/Controller');
dump($router->getRouteCollection());
$params = $request->request->all();
$files = $request->files->all();
$data = array_replace_recursive($params, $files);
$form->submit($data);
submit
как показано выше$rules = new Assert\Collection([
"items" => new Assert\Required([
new Assert\NotBlank(),
new Assert\Callback(function ($value, ExecutionContextInterface $context) {
$validator = $context->getValidator();
$violations = $validator->validate($value, new Assert\Type('array'));
if ($violations->count() > 0) {
/** @var ConstraintViolationInterface $violation */
foreach ($violations as $violation) {
$context
->buildViolation($violation->getMessage(), $violation->getParameters())
->atPath('items')
->addViolation()
;
}
return;
}
$violations = $validator->validate($value, new Assert\All([
new Assert\Type('array'),
new Assert\Collection([
"id" => new Assert\NotBlank(),
"quantity" => new Assert\NotBlank(),
])
]));
/** @var ConstraintViolationInterface $violation */
foreach ($violations as $violation) {
$context
->buildViolation($violation->getMessage(), $violation->getParameters())
->atPath('items'. $violation->getPropertyPath())
->addViolation()
;
}
}),
]),
]);
$validator = Validation::createValidator();
$data = [
'items' => [
[
'id' => 'id',
'quantity' => 'quantity',
],
],
];
dump($validator->validate($data, $rules)); // Ok
$data = [
'items' => 1,
];
dump($validator->validate($data, $rules)); // Ko
$data = [
'items' => [
[
'id' => 'id',
'quantity' => 'quantity',
],
[
'id2' => 'id',
'quantity2' => 'quantity',
]
],
];
dump($validator->validate($data, $rules)); // Ko
ObjectNormalizer
имеет несколько больше зависимостей для полноценной его работыpublic function submitAction(SerializerInterface $serializer, Request $request)
{
if ($request->isXmlHttpRequest()) {
$data = $request->getContent();
$result = $serializer->deserialize($data, SiteCreateDto::class, 'json');
var_dump($result); exit;
}
}
ObjectNormalizer
не помог, то надо будет написать свой: https://symfony.com/doc/current/serializer/custom_... <?php
namespace App\Controller;
use App\Entity\User;
use App\Service\UserService;
use Symfony\Component\DependencyInjection\ServiceLocator;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Security\Core\Exception\AccessDeniedException;
use Symfony\Component\Security\Core\Security;
use Twig\Environment;
interface AdminControllerInterface
{
public function index(): Response;
public function read(string $id): Response;
}
class UserController implements AdminControllerInterface
{
/**
* Security - объект-helper, он содержит в себе AuthorizationCheckerInterface
*
* @var Security
*/
private $security;
/**
* @var ServiceLocator
*/
private $controllerLocators;
public function __construct(Security $security, ServiceLocator $controllerLocators)
{
$this->security = $security;
$this->controllerLocators = $controllerLocators;
}
public function index(): Response
{
$role = $this->getRole();
if (!$this->controllerLocators->has($role)) {
throw new AccessDeniedException();
}
/** @var AdminControllerInterface $controller */
$controller = $this->controllerLocators->get($role);
return $controller->index();
}
public function read(string $id): Response
{
$role = $this->getRole();
if (!$this->controllerLocators->has($role)) {
throw new AccessDeniedException();
}
/** @var AdminControllerInterface $controller */
$controller = $this->controllerLocators->get($role);
return $controller->read($id);
}
private function getRole(): string
{
// Для простоты представим, что роль у пользователя одна. Иначе искать среди ролей
// ROLE_SUPER_ADMIN и ROLE_CUSTOMER_ADMIN и возвращаем с соответствующим приоритетом
return current($this->security->getToken()->getRoles());
}
}
class SuperAdminController implements AdminControllerInterface
{
private $userService;
/**
* @var Environment
*/
private $twig;
public function __construct(
UserService $userService,
Environment $twig
) {
$this->userService = $userService;
$this->twig = $twig;
}
public function index(): Response
{
$users = $this->userService->getAll();
return new Response($this->twig->render('admin/users.html.twig', [
'users' => $users
]));
}
public function read(string $id): Response
{
$user = $this->userService->getById($id);
return new Response($this->twig->render('admin/user.html.twig', [
'user' => $user
]));
}
}
class CustomerAdminController implements AdminControllerInterface
{
private $userService;
/**
* @var Security
*/
private $security;
/**
* @var Environment
*/
private $twig;
public function __construct(
UserService $userService,
Environment $twig
) {
$this->userService = $userService;
$this->twig = $twig;
}
public function index(): Response
{
/** @var User $user */
$user = $this->security->getUser();
$users = $this->userService->findByRoleAndWorkspaceId(
User::ROLE_TEAM_MEMBER,
$user->getWorkspace()->getId()
);
return new Response($this->twig->render('user/users.html.twig', [
'users' => $users
]));
}
public function read(string $id): Response
{
$user = $this->userService->getByIdAndWorkspaceId($id);
return new Response($this->twig->render('user/user.html.twig', [
'user' => $user
]));
}
}
app.admin_controller_locator:
class: Symfony\Component\DependencyInjection\ServiceLocator
arguments:
-
ROLE_SUPER_ADMIN: '@App\Controller\SuperAdminController'
ROLE_CUSTOMER_ADMIN: '@App\Controller\CustomerAdminController'
tags: ['container.service_locator']
UniqueEntity
работает только с Entity. Если хотите валидировать таким образом DTO, то придется написать свой валидатор. За основу можно взять встроенный: https://github.com/symfony/symfony/blob/master/src...