$ids = [1, 2, 3, 4];
$this->getEntityManager()->getConnection()
->executeStatement('UPDATE some_table SET some_field = ? WHERE id IN (?)', [
'value',
$ids,
], [
1 => Connection::PARAM_INT_ARRAY,
]);
$builder = $this->getEntityManager()->getConnection()->createQueryBuilder();
$builder
->update('some_table')
->set('some_field', ':value')
->where($builder->expr()->in('id', ':ids'))
->setParameter('value', 'value')
->setParameter('ids', $ids, Connection::PARAM_INT_ARRAY)
;
$builder->execute()
$this->getEntityManager()
->createQuery('UPDATE App\Entity\SomeEntity se SET se.someValue = :value WHERE se.id IN (:ids)')
->execute(new ArrayCollection([
new Parameter('value', 'value'),
new Parameter('ids', $ids),
]))
);
$builder = $this->createQueryBuilder('se');
$builder
->update()
->set('se.someValue', ':value')
->where($builder->expr()->in('uu.id', ':ids'))
->setParameter('value', 'value')
->setParameter('ids', $ids)
;
$builder->getQuery()->execute();
\App\Entity\Group::__toString
, либо добавьте опцию choice_label->add('group', null, [
'choice_label' => 'getName', // Метод, который вернет название группы
])
$post = new Post();
// Заполняем поля, которые присутствуют в форме
$post->setPublishedAt(new \DateTime());
$post->setTitle('New title');
// Если объекты не используются, то заполнять надо массив
// $post = [];
// $post['publishedAt'] = new \DateTime();
// $post['title'] = 'New title';
$form = $this->createForm(PostType::class, $post);
// ...
return $this->render('post.html.twig', [
'form' => $form->createView(),
])
$builder->get('publishedAt')->setData(new \DateTime());
$builder->get('title')->setData('New title');
$builder->addEventListener(FormEvents::PRE_SET_DATA, function (FormEvent $event) {
$data = $event->getData();
if ($data !== null) {
return;
}
$event->setData([
'title' => 'New title',
'publishedAt' => new \DateTime(),
]);
});
# servces.yaml
services:
Monolog\Handler\TelegramBotHandler:
arguments:
- '%env(TELEGRAM_BOT_KEY)%'
- '%env(TELEGRAM_CHANNEL)%'
# monolog.yaml
monolog:
handlers:
message:
type: fingers_crossed
action_level: error
excluded_http_codes: [ 400, 401, 403, 404 ]
buffer_size: 50
handler: deduplicated
deduplicated:
type: deduplication
handler: telegram
telegram: # Важна только эта часть
type: service
id: Monolog\Handler\TelegramBotHandler
level: debug
use Symfony\Component\Form\AbstractTypeExtension;
use Symfony\Component\Form\FormBuilderInterface;
class BundleFormTypeExtension extends AbstractTypeExtension
{
public static function getExtendedTypes(): iterable
{
return [BundleFormType::class];
}
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->remove('someField');
}
}
namespace App\Doctor;
use App\Doctor\Check\CheckInterface;
final class Doctor
{
/**
* @var CheckInterface[]
*/
private iterable $checks;
public function __construct(iterable $checks)
{
$this->checks = $checks;
}
/**
* @return Violation[]|array
*/
public function check(): array
{
$violations = [];
foreach ($this->checks as $check) {
$violations[$check->feature()] = array_merge($violations[$check->feature()] ?? [], $check->violations());
}
return $violations;
}
}
namespace App\Doctor\Check;
use App\Doctor\Violation;
interface CheckInterface
{
public function feature(): string;
/**
* @return Violation[]
*/
public function violations(): array;
}
services:
_instanceof:
App\Doctor\Check\CheckInterface:
tags:
- { name: app.doctor.check }
App\Doctor\Doctor:
arguments:
$checks: !tagged app.doctor.check
public function doctorAction(): JsonResponse
{
return $this->json($this->doctor->check());
}
{
"foo": [], // Ok
"bar": [
{ "message": "Отсутствуют статусы", "treatment": "Добавьте статусы" }
]
}
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\Serializer\Normalizer\AbstractObjectNormalizer;
use Symfony\Component\Serializer\Normalizer\DenormalizerInterface;
use Symfony\Component\Serializer\Normalizer\ObjectNormalizer;
class MyObjectDenormalizer implements DenormalizerInterface
{
private ObjectNormalizer $objectNormalizer;
private EntityManagerInterface $entityManager;
public function __construct(ObjectNormalizer $objectNormalizer, EntityManagerInterface $entityManager)
{
$this->objectNormalizer = $objectNormalizer;
$this->entityManager = $entityManager;
}
public function denormalize($data, string $type, string $format = null, array $context = [])
{
if ($id = $data['id'] ?? null) {
$object = $this->entityManager->getRepository($type)->find($id);
$context = [
AbstractObjectNormalizer::OBJECT_TO_POPULATE => $object,
];
unset($data['id']);
}
return $this->objectNormalizer->denormalize($data, $type, $format, $context);
}
public function supportsDenormalization($data, string $type, string $format = null)
{
return $this->objectNormalizer->supportsDenormalization($data, $type, $format);
}
}
/comment/{id}/edit
), т.к. есть возможность подменить id и отредактировать другую сущность (к которой, к примеру, у пользователя доступа нет) use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpKernel\Event\ExceptionEvent;
use Symfony\Component\HttpKernel\Event\ResponseEvent;
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
use Symfony\Component\Security\Core\Exception\AccessDeniedException;
use Symfony\Component\Security\Http\Event\LogoutEvent;
class LogoutRedirectSubscriber implements EventSubscriberInterface
{
private const KEY = 'logout';
private UrlGeneratorInterface $urlGgenerator;
public static function getSubscribedEvents()
{
return [
ExceptionEvent::class => ['onException', 2], // Before \Symfony\Component\Security\Http\Firewall\ExceptionListener
ResponseEvent::class => 'onResponse',
LogoutEvent::class => 'onLogout',
];
}
public function __construct(UrlGeneratorInterface $urlGgenerator)
{
$this->urlGgenerator = $urlGgenerator;
}
public function onException(ExceptionEvent $event): void
{
if (!$event->isMasterRequest()) {
return;
}
$exception = $event->getThrowable();
if (!$exception instanceof AccessDeniedException) {
return;
}
$session = $event->getRequest()->getSession();
if ($session->has(self::KEY)) {
$event->setResponse(new RedirectResponse($this->urlGgenerator->generate('index')));
$event->stopPropagation();
}
}
public function onResponse(ResponseEvent $event): void
{
if (!$event->isMasterRequest()) {
return;
}
if ($event->getResponse()->getStatusCode() >= 300) {
return;
}
$session = $event->getRequest()->getSession();
if ($session->has(self::KEY)) {
$session->remove(self::KEY);
}
}
public function onLogout(LogoutEvent $event): void
{
$event->getRequest()->getSession()->set(self::KEY, true);
}
}
options
и будете проверять их в обработчике LogoutEvent
Kernel.php
разбирать структуру папок и подключать все динамически там.migrations/
src/
-- Controller/
---- User/
---- ModuleName/
-- Entity/
---- User/
---- ModuleName/
-- User/
--- Dto/
--- Repository/
--- Service/
-- ModuleName/
--- Dto/
--- Repository/
--- Service/
// src/AppBundle/Form/CustomerType.php
public function buildForm(FormBuilderInterface $builder, array $options)
{
//....
$builder
->add('phones',CollectionType::class, array(
'by_reference' => false,
// ...
));
//....
}
class Customers implements UserInterface
{
/**
* @ORM\OneToMany(targetEntity="AppBundle\Entity\Phone", mappedBy="customer_id", cascade={"persist", "remove", "merge"})
*/
private $phones; // Это же коллекция, нужно множественное число, чтобы работали adder и remover
public function addPhone(Phone $phone)
{
$phone->setCustomer($this);
$this->phones->add($phone);
}
public function removePhone(Phone $phone)
{
$phone->setCustomer(null);
$this->phones->removeElement($phone);
}
}
// src/AppBundle/Form/PhoneType.php
// $builder->add('customerId', HiddenType::class); // не нужен
bin/console fos:user:create username em@ai.il 'p@55w0rd'
./**
* @psalm-suppress PropertyNotSetInConstructor
*/
class CreateCommand extends AbstractCommand
{
private DocumentManager $documentManager;
private ValidatorInterface $validator;
private PasswordGenerator $passwordGenerator;
private AdministratorMapper $mapper;
public function __construct(
DocumentManager $documentManager,
ValidatorInterface $validator,
PasswordGenerator $passwordGenerator,
AdministratorMapper $mapper
) {
parent::__construct();
$this->documentManager = $documentManager;
$this->validator = $validator;
$this->passwordGenerator = $passwordGenerator;
$this->mapper = $mapper;
}
/**
* @psalm-suppress MissingReturnType
*/
protected function configure()
{
$this
->setName('app:administrator:create')
->addArgument('username', InputArgument::REQUIRED, 'Username')
->addOption('password', 'p', InputOption::VALUE_REQUIRED, 'Password')
->setDescription('Creates administrator')
;
}
protected function execute(InputInterface $input, OutputInterface $output)
{
/** @var string $username */
$username = $input->getArgument('username');
/** @var string|null $plainPassword */
$plainPassword = $input->getOption('password');
if (!$plainPassword) {
$plainPassword = $this->passwordGenerator->generate();
}
$model = new AdministratorModel();
$model->enabled = true;
$model->username = $username;
$model->password = $plainPassword;
$errors = $this->validator->validate($model);
if (\count($errors) > 0) {
$this->io->error('Can\'t create administrator');
$this->printConstraintViolations($errors);
return 1;
}
$administrator = $this->mapper->map($model);
$this->documentManager->persist($administrator);
$this->documentManager->flush();
$this->io->writeln(sprintf('Administrator <info>%s</info> with password <info>%s</info> has been created', $administrator->getUsername(), $plainPassword));
return 0;
}
}
bin/console app:administrator:create vasx3
maker:
root_namespace: 'App\Common'
mappings:
App:
is_bundle: false
type: annotation
dir: '%kernel.project_dir%/src/Entity'
prefix: 'App\Entity'
alias: App
AppСommon:
is_bundle: false
type: annotation
dir: '%kernel.project_dir%/src/Common/Entity'
prefix: 'App\Common\Entity'
alias: AppСommon
specs
всегда один и тот же набор объектов и нет динамических параметров, то вложенные формы вполне могут сработать /** @var AuthorizationCheckerInterface $authorizationChecker */
if (!$authorizationChecker->isGranted('ROLE_USER')) {
throw new AccessDeniedException();
}
/** @var AuthorizationCheckerInterface $authorizationChecker */
if (!$authorizationChecker->isGranted('IS_AUTHENTICATED_REMEMBERED')) {
throw new AccessDeniedException();
}
use Symfony\Component\HttpFoundation\JsonResponse;
$data = [
'List' => [
0 => [
'id' => 'id0',
],
1 => [
'id' => 'id1',
],
],
];
dump(
new JsonResponse(
json_encode($data, JsonResponse::DEFAULT_ENCODING_OPTIONS | JSON_FORCE_OBJECT),
200,
[],
true
)
);
// or
$response = new JsonResponse($data);
$response->setEncodingOptions(JsonResponse::DEFAULT_ENCODING_OPTIONS | JSON_FORCE_OBJECT);
dump($response->getContent());
use Pagerfanta\Pagerfanta;
class PaginatedCollection
{
private int $page;
private int $size;
private int $total;
private int $pages;
private array $items;
public function __construct(Pagerfanta $pagerfanta)
{
$this->page = $pagerfanta->getCurrentPage();
$this->size = $pagerfanta->getMaxPerPage();
$this->total = $pagerfanta->getNbResults();
$this->pages = $pagerfanta->getNbPages();
$this->items = iterator_to_array($pagerfanta);
}
public function getPage(): int
{
return $this->page;
}
public function getSize(): int
{
return $this->size;
}
public function getTotal(): int
{
return $this->total;
}
public function getPages(): int
{
return $this->pages;
}
public function getItems(): array
{
return $this->items;
}
}
// Repository
public function findPaginatedBySupplierId(int $supplier_id)
{
return new Pagerfanta(DoctrineORMAdapter($this->getSupplierIdQueryBuilder($supplier_id)));
}
private function getSupplierIdQueryBuilder(int $supplier_id)
{
$qb = $this->createQueryBuilder('sj');
$qb = $qb
->select("sj")
->orderBy('sj.datetime', 'ASC')
->andWhere("sj.supplier = :supplier_id")
->setParameter("supplier_id", $supplier_id);
return $qb;
}
// Controller
public function action()
{
// ...
return $this->json($this->paginatedCollection($repository->findPaginatedBySupplierId($id), $request));
}
// AbstractController
protected function paginatedCollection(Pagerfanta $pagination, Request $request, int $size = 20): PaginatedCollection
{
$pagination = $this->paginate($pagination, $request, $size);
return new PaginatedCollection($pagination);
}
protected function paginate(Pagerfanta $pagination, Request $request, int $size = 20): Pagerfanta
{
$pagination->setMaxPerPage($size);
$pagination->setCurrentPage($request->query->getInt('page', 1));
return $pagination;
}
{
"page": 1,
"size": 20,
"total": 76,
"pages": 4,
"items": [...]
}
/**
* @var \App\Entity\IpContract[]
*
* @ORM\OneToMany(targetEntity="App\Entity\IpContract", mappedBy="users", orphanRemoval=true)
*/
private $ipContracts;