<?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...services:
_defaults:
autowire: true
autoconfigure: true
bind:
App\Repository\Repository $cachedRepository: '@App\Repository\User\CachedUserRepository'
App\Repository\Repository: '@App\Repository\User\DoctrineUserRepository'
App\Entity\UniqueEntityInterface: '@App\Entity\User'
user_exists_checker:
class: App\ExistsChecker
bind:
App\Repository\Repository: '@App\Repository\User\ApiUserRepository'user_exists_checker:
class: App\ExistsChecker
bind:
App\Repository\Repository: '@App\Repository\User\ApiUserRepository'_defaults:
autowire: true
autoconfigure: true
bind:
App\Repository\Repository $cachedRepository: '@App\Repository\User\CachedUserRepository'App\Repository\Repository $repository будете использовать App\Repository\Repository $cachedRepository, то вам придет App\Repository\User\CachedUserRepository composer.json для них соответствующий неймспейс в секции autoload. Но по факту в итоге у вас не получится интегрировать эту библиотеку с symfony (точнее получится, но это будут костыли), т.к. невозможно пробросить свои зависимости в конструктор"autoload": {
"psr-4": { "Longman\\TelegramBot\\Commands\\": "commands/" }
}, /users/123 и /users/123/всечтоугодно/my и /my/всечтоугодноconfig/routes/annotations.yaml в config/routes.yml и отдельно прописать нужный контроллер в конце списка:config/routes.ymlcontrollers:
resource: ../src/Controller/
type: annotation
page_controller:
resource: ../src/Controller/TextPageController.php
type: annotationconfig/routes/dev/* - тут все стандартно-------------------------- -------- -------- ------ -----------------------------------
Name Method Scheme Host Path
-------------------------- -------- -------- ------ -----------------------------------
_twig_error_test ANY ANY ANY /_error/{code}.{_format}
_wdt ANY ANY ANY /_wdt/{token}
_profiler_home ANY ANY ANY /_profiler/
_profiler_search ANY ANY ANY /_profiler/search
_profiler_search_bar ANY ANY ANY /_profiler/search_bar
_profiler_phpinfo ANY ANY ANY /_profiler/phpinfo
_profiler_search_results ANY ANY ANY /_profiler/{token}/search/results
_profiler_open_file ANY ANY ANY /_profiler/open
_profiler ANY ANY ANY /_profiler/{token}
_profiler_router ANY ANY ANY /_profiler/{token}/router
_profiler_exception ANY ANY ANY /_profiler/{token}/exception
_profiler_exception_css ANY ANY ANY /_profiler/{token}/exception.css
// Controllers
index ANY ANY ANY /
// Page Controller
page_show ANY ANY ANY /{pageSlug}
page_item ANY ANY ANY /{pageSlug}/{parameters}
-------------------------- -------- -------- ------ -----------------------------------class AccountRepository extends ServiceEntityRepository
{
public function __construct(RegistryInterface $registry)
{
parent::__construct($registry, Account::class);
}
}class AccountRepository extends \Doctrine\ORM\EntityRepository
{
}App\Repository\AccountRepository:
arguments:
- 'App\Entity\Account' # Entity class
factory: ['@doctrine', 'getRepository'] If you are building a traditional web application:
composer create-project symfony/website-skeleton my_projectIf you are building a microservice, console application or API
composer create-project symfony/skeleton my_projectsymfony/skeleton и для традиционного сайта. $constraint = new Assert\Collection(
[
'fields' => [
'cf_sub_products' => [
new Assert\NotBlank(),
new Assert\Type('array'),
new Assert\All([
new Assert\Collection([
'fields' => [
"size" => [
new Assert\NotBlank(),
],
"cf_product_id" => [
new Assert\NotBlank(),
],
"enabled" => [
new Assert\NotBlank(),
],
"price" => [
new Assert\NotBlank(),
],
"sku" => [
new Assert\NotBlank(),
],
],
])
])
]
]
]
);
$violations = $validator->validate($body, $constraint); 'toEmail' => [
new Assert\NotBlank(),
new Assert\Type('array'),
new Assert\All([
'constraints' => [
new Assert\NotBlank(),
new Assert\Email(),
],
])
] security.ymlsecurity:
access_control:
- { path: ^/ }RequestVoter.phpuse Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\Authorization\Voter\VoterInterface;
use Symfony\Component\Security\Core\Security;
class RequestVoter implements VoterInterface
{
/**
* @var Security
*/
private $security;
public function __construct(Security $security)
{
$this->security = $security;
}
/**
* @inheritDoc
*/
public function vote(TokenInterface $token, $subject, array $attributes)
{
if (!$subject instanceof Request) {
return self::ACCESS_ABSTAIN;
}
$route = $subject->attributes->get('_route');
$routeRole = $this->getRoleByRoute($route);
if ($this->security->isGranted($routeRole)) {
return self::ACCESS_GRANTED;
}
return self::ACCESS_DENIED;
}
protected function getRoleByRoute(string $route): string
{
// ...
}
} {% transchoice count with { '%count%': count } %}
%count% яблоко|%count% яблока|%count% яблок
{% endtranschoice %} use Symfony\Component\Validator\Constraints as Assert;
use Symfony\Component\Validator\Context\ExecutionContextInterface;
class Model
{
/**
* @var string
*/
public $foo;
/**
* @var string
*/
public $bar;
/**
* @Assert\Callback()
*
* @param ExecutionContextInterface $context
* @param $payload
*/
public function validateFooBar(ExecutionContextInterface $context, $payload)
{
$fooViolations = $context->getValidator()->validate($this->foo, new Assert\NotBlank());
$barViolations = $context->getValidator()->validate($this->bar, new Assert\NotBlank());
if ($fooViolations->count() > 0 && $barViolations->count() > 0) {
$context->buildViolation('foo или bar должны быть заполнены')
->addViolation()
;
}
}
} $violations = $this->get('validator')->validate($dto);$dto = $this->get('serializer')->deserialize(
$request->getContent(),
DTO::class
);public function editAction(DTO $dto)
{
}CustomUserMessageAuthenticationException - подкласс AuthenticationException) и обрабатывает их по-свойму. $process = new Process("bin/console app:check-api $orderId > /dev/null 2>&1 &");{% block password_widget %}
<div class="form-control">
{{ block('password_widget') }}
</div>
{% endblock %}{% form_theme form _self %}
{% block password_widget %}
<div class="form-control">
{{ block('password_widget') }}
</div>
{% endblock %}{% block password_widget %}
<div class="form-control">
{%- set type = type|default('password') -%}
{{ block('form_widget_simple') }}
</div>
{% endblock %}FrameworkBundle/Resources/views/Form лежат шаблоны для php-форм