<?php
namespace App\Form;
use App\Entity\Brand;
use App\Entity\Model;
use App\Entity\Modification;
use App\Entity\Series;
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\NumberType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Form\FormEvent;
use Symfony\Component\Form\FormEvents;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Validator\Constraints as Assert;
class ModificationType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add("name", TextType::class, [
"attr" => ["class" => "form-control"],
"label" => "Наименование",
"label_attr" => [
"class" => "col-sm-2 form-control-label"
],
"constraints" => [
new Assert\NotBlank(),
new Assert\Length(["max" => 255]),
],
"required" => true,
])
->add("alt_name", TextType::class, [
"attr" => ["class" => "form-control"],
"label" => "Альтернативное наименование",
"label_attr" => [
"class" => "col-sm-2 form-control-label"
],
"constraints" => [
new Assert\NotBlank(),
new Assert\Length(["max" => 255]),
],
"required" => true,
])
->add("seo_name", TextType::class, [
"attr" => ["class" => "form-control"],
"label" => "SEO Name",
"label_attr" => [
"class" => "col-sm-2 form-control-label"
],
"constraints" => [
new Assert\NotBlank(),
new Assert\Length(["max" => 100]),
],
"required" => true,
])
->add("power_kwt", NumberType::class, [
"attr" => ["class" => "form-control"],
"label" => "Мощность кВт",
"label_attr" => [
"class" => "col-sm-2 form-control-label"
],
"constraints" => [
new Assert\NotBlank(),
new Assert\Positive(),
],
"empty_data" => 0,
"required" => true,
])
->add("power_horse", NumberType::class, [
"attr" => ["class" => "form-control"],
"label" => "Мощность л.с.",
"label_attr" => [
"class" => "col-sm-2 form-control-label"
],
"constraints" => [
new Assert\NotBlank(),
new Assert\Positive()
],
"empty_data" => 0,
"required" => true,
])
->add("year_from", ChoiceType::class, [
"attr" => ["class" => "form-control"],
"label" => "Год начала производства",
"label_attr" => [
"class" => "col-sm-2 form-control-label"
],
"choices" => $this->getYears(),
"constraints" => [
new Assert\NotBlank(),
new Assert\Length(["max" => 4]),
],
"required" => true,
])
->add("year_to", ChoiceType::class, [
"attr" => ["class" => "form-control"],
"label" => "Год завершения производства",
"label_attr" => [
"class" => "col-sm-2 form-control-label"
],
"choices" => $this->getYears(),
"empty_data" => "н.в.",
"constraints" => [
new Assert\NotBlank(),
new Assert\Length(["max" => 4]),
],
"required" => false,
])
->add("brand", EntityType::class, [
"label" => "Бренд",
"label_attr" => [
"class" => "col-sm-2 form-control-label"
],
"class" => Brand::class,
"choice_label" => function ($brand) {
return $brand->getName();
},
"attr" => [
"class" => "form-control select"
],
"constraints" => [
new Assert\NotBlank()
]
])
->add("model", ChoiceType::class, [
"label" => "Модель",
"label_attr" => [
"class" => "col-sm-2 form-control-label"
],
"choices" => [],
"attr" => [
"class" => "form-control select"
],
"constraints" => [
new Assert\NotBlank()
],
"disabled" => true
])
->add("series", ChoiceType::class, [
"label" => "Серия",
"label_attr" => [
"class" => "col-sm-2 form-control-label"
],
"choices" => [],
"attr" => [
"class" => "form-control select"
],
"constraints" => [
new Assert\NotBlank()
],
"disabled" => true
]);
$builder->get("brand")->addEventListener(
FormEvents::POST_SUBMIT,
function (FormEvent $event) {
$form = $event->getForm();
$brand_id = $event->getData();
$form->getParent()->add("model", EntityType::class, [
"label_attr" => [
"class" => "col-sm-2 form-control-label"
],
"attr" => [
"class" => "form-control select"
],
"class" => Model::class,
"query_builder" => function (EntityRepository $er) use ($brand_id) {
return $er->createQueryBuilder("m")
->andWhere("m.brand = :brand_id")
->setParameter("brand_id", $brand_id)
->orderBy("m.name", "ASC");
},
"choice_label" => function ($entity)
{
return $entity->getName();
},
"constraints" => [
new Assert\NotBlank()
],
"required" => true
]);
$form->getParent()->add("series", EntityType::class, [
"label_attr" => [
"class" => "col-sm-2 form-control-label"
],
"attr" => [
"class" => "form-control select"
],
"class" => Series::class,
"query_builder" => function (EntityRepository $er) use ($brand_id) {
return $er->createQueryBuilder("s")
->andWhere("s.brand = :brand_id")
->setParameter("brand_id", $brand_id)
->orderBy("s.name", "ASC");
},
"choice_label" => function ($entity)
{
return $entity->getName();
},
"constraints" => [
new Assert\NotBlank()
],
"required" => true
]);
}
);
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
"data_class" => Modification::class,
]);
}
/**
* @return array
*/
private function getYears(): array
{
$years = [];
for ($i = date("Y"); $i >= 1955; $i--) {
$years[$i] = $i;
}
return $years;
}
}
security:
encoders:
App\Entity\User:
algorithm: auto
# https://symfony.com/doc/current/security.html#where-do-users-come-from-user-providers
providers:
app_security_user_provider:
id: App\Security\UserProvider
# registration:
# pattern: ^/secure.registration
# stateless: true
# anonymous: true
firewalls:
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
authorization:
pattern: ^/authorization
security: false
main:
anonymous: ~
stateless: true
provider: app_security_user_provider
guard:
authenticators:
- App\Security\Authenticator
# activate different ways to authenticate
# https://symfony.com/doc/current/security.html#firewalls-authentication
# https://symfony.com/doc/current/security/impersonating_user.html
# switch_user: true
# Easy way to control access for large sections of your site
# Note: Only the *first* access control that matches will be used
access_control:
# - { path: ^/profile, roles: ROLE_USER }
// throw exception
$this->denyAccessUnlessGranted(UserVoter::READ["read"], User::class, "Вам запрещено просматривать пользователей.");
// or
// return boolean
$this->isGranted(UserVoter::READ["read"], User::class)
class UserVoter extends Voter implements IVoter
{
public const CREATE_USERS = 'create_users';
public const EDIT_USERS = 'edit_users';
public const DELETE_USERS = 'delete_users';
public const VIEW_USERS = 'view_users';
public const VIEW_CONTACTS = 'view_contacts';
public const SET_PRIVILEGES_USERS = 'set_privileges_users';
...
...
$permissions = [];
try {
if (is_a($user->getGroup(), UserGroup::class)) {
$permissions = $user->getGroup()->getPermissions();
}
foreach ($permissions as $permission) {
if (in_array($permission, $this->getAttributes())) {
return true;
}
}
return false;
}catch (Exception $exception) {
return false;
}
...
parameters:
lang: ru
# default configuration for services in *this* file
_defaults:
autowire: true # Automatically injects dependencies in your services.
autoconfigure: true # Automatically registers your services as commands, event subscribers, etc.
bind:
$default_lang: '%lang%'
services:
app.service.lang:
class: App\Service\Lang
arguments: ['@request_stack', '@?']
<?php
namespace App\Service;
use Symfony\Component\HttpFoundation\RequestStack;
/**
* Class Lang
* @package App\Service
*/
class Lang
{
/** @var string */
private $lang;
/**
* Lang constructor.
* @param RequestStack $requestStack
* @param $default_lang
*/
public function __construct(RequestStack $requestStack, $default_lang)
{
$this->lang = $requestStack->getCurrentRequest()->get("lang", $default_lang);
}
/**
* @return mixed|string
*/
public function get()
{
return $this->lang;
}
}
public function myMethod(Lang $lang)
{
$value = $lang->get()
}
<?php
namespace App\Classes\Entity;
/**
* Class AbstractEntity
* @package App\Classes\Entity
*/
abstract class AbstractEntity
{
/** @var string */
protected $language = "ru";
/**
* @param string $language
*/
public function setLanguage(string $language): void
{
$this->language = $language;
}
}
<?php
namespace App\Entity;
use App\Classes\Entity\AbstractEntity;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\ORM\Mapping\JoinColumn;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Constraints\NotNull;
use Symfony\Component\Validator\Mapping\ClassMetadata;
/**
* @ORM\Entity(repositoryClass="App\Repository\CategoryRepository")
* @ORM\Table(name="categories")
*/
class Category extends AbstractEntity
{
/**
* @ORM\Column(type="integer")
* @ORM\Id
* @ORM\GeneratedValue
*/
private $id;
/**
* @ORM\Column(name="name", length=64)
*/
private $name_ru;
/**
* @ORM\Column(length=64, nullable=true)
*/
private $name_cn;
/**
* @ORM\Column(length=64, nullable=true)
*/
private $name_en;
/**
* @return mixed
*/
public function getId()
{
return $this->id;
}
/**
* @param $name
* @param string $lang
*/
public function setName($name, $lang)
{
$this->{"name_$lang"} = $name;
}
/**
* @return string
*/
public function getName()
{
return $this->{"name_$this->language"};
}
}
<?php
namespace App\Listeners;
use App\Classes\Entity\AbstractEntity;
use Doctrine\Persistence\Event\LifecycleEventArgs;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\RequestStack;
/**
* Class LanguageEntityListener
* @package App\Listeners
*/
class LanguageEntityListener
{
/** @var string */
private $language = "ru";
/** @var Request */
private $request;
/**
* LanguageEntityListener constructor.
* @param RequestStack $requestStack
*/
public function __construct(RequestStack $requestStack)
{
$this->request = $requestStack->getCurrentRequest();
$this->language = $this->request->get("lang", "ru");
}
public function postLoad(LifecycleEventArgs $event)
{
$entity = $event->getObject();
if (is_a($entity, AbstractEntity::class)) {
$entity->setLanguage($this->language);
}
}
}
services:
app.listeners.language_entity_listener:
class: App\Listeners\LanguageEntityListener
arguments: ['@request_stack']
tags:
- { name: doctrine.event_listener, event: postLoad, method: postLoad }
server {
listen 80;
client_max_body_size 208M;
access_log /var/log/nginx/secure.access.log;
error_log /var/log/nginx/secure.error.log error;
root /www/public;
add_header "Access-Control-Allow-Origin" "*";
add_header "Access-Control-Allow-Headers" "Origin, X-Requested-With, Content-Type, Accept, Authorization";
add_header "Access-Control-Request-Methods" "GET, POST, OPTIONS";
location / {
try_files $uri $uri/ /secure.php?$query_string;
}
location ~ \.php$ {
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass app:9000;
fastcgi_index secure.php;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param PATH_INFO $fastcgi_path_info;
}
}
class ServiceRepository extends NestedTreeRepository
{
...
/**
* @param Service $node
* @return void
* @throws ORMException
* @throws OptimisticLockException
*/
public function removeTree(Service $node)
{
$this->createQueryBuilder("s")
->delete()
->where("s.lft >= :lft")->setParameter("lft", $node->getLft())
->andWhere("s.rgt <= :rgt")->setParameter("rgt", $node->getRgt())
->andWhere("s.root = :root")->setParameter("root", $node->getRoot())
->getQuery()
->execute();
$em = $this->getEntityManager();
$em->beginTransaction();
$repository = $em->getRepository("App:Service");
$refreshLeftAndRight = function($root, $left) use ($repository, &$refreshLeftAndRight) {
$right = $left + 1;
$children = $repository->findBy(['parent' => $root,]);
foreach ($children as $entity) {
$right = $refreshLeftAndRight($entity, $right);
}
$root->setlft($left);
$root->setRgt($right);
return $right + 1;
};
foreach ($repository->findBy(["parent" => null]) as $rootEntry) {
$refreshLeftAndRight($rootEntry, 1);
}
$em->flush();
$em->commit();
}
...
# JsonRequest
App\Service\JsonRequest:
calls:
- [setRequest, ['@request_stack']]
<?php
namespace App\Service;
use Exception;
use Symfony\Component\HttpFoundation\RequestStack;
/**
* Class JsonRequest
* @package App\Service
*/
class JsonRequest
{
private $json_object;
public function __construct()
{
}
/**
* @param string $key
* @param bool $default
* @return mixed
*/
public function get(string $key, $default = null)
{
try {
$properties = explode(".", $key);
$buf = $this->json_object;
foreach ($properties as $property) {
if (property_exists($buf, $property)) {
$buf = $buf->{$property};
} else {
return $default;
}
}
return $buf;
} catch (Exception $e) {
return $default;
}
}
/**
* @param string $key
* @return bool
*/
public function has(string $key)
{
return property_exists($this->json_object, $key);
}
/**
* @param RequestStack $request
*/
public function setRequest(RequestStack $request): void
{
$this->json_object = json_decode($request->getCurrentRequest()->getContent());
}
}
<?php
define('ENV', basename(__DIR__));
require '../../engine/bootstrap.php';