فهرست منبع

working fixtures insertion

Olivier Massot 2 سال پیش
والد
کامیت
57d1fa5542

+ 1 - 1
.env.docker

@@ -12,7 +12,7 @@ CORS_ALLOW_ORIGIN=^https?:\/\/(localhost|127\.0\.0\.1|(local.(admin|app|app\-v3|
 
 ###> api v1 ###
 API_LEG_BASE_URL=http://nginx/
-###< files management ###
+###< api v1 ###
 
 ###> BlackFire configuration ###
 BLACKFIRE_CLIENT_ID=988fcba8-552d-48df-a9c2-035c76535b69

+ 0 - 57
.env.preprod

@@ -1,57 +0,0 @@
-###> symfony/framework-bundle ###
-APP_DEBUG=1
-###< symfony/framework-bundle ###
-
-###> doctrine/doctrine-bundle ###
-DATABASE_URL=mysql://root:mysql2iopenservice369566@preprod:3306/opentalent?serverVersion=5.7
-###< doctrine/doctrine-bundle ###
-
-###> nelmio/cors-bundle ###
-CORS_ALLOW_ORIGIN=^https?://(localhost|127\.0\.0\.1)(:[0-9]+)$
-###< nelmio/cors-bundle ###
-
-###> api v1 ###
-API_LEG_BASE_URL=https://api.preprod.opentalent.fr/api
-###< files management ###
-
-###> typo3 client ###
-TYPO3_BASE_URI=http://preprod.opentalent.fr/ohcluses
-###< typo3 client ###
-
-###> BlackFire configuration ###
-BLACKFIRE_CLIENT_ID=988fcba8-552d-48df-a9c2-035c76535b69
-BLACKFIRE_CLIENT_TOKEN=8cfbeb263d044da9678dc2612531504da3790c308da7448e35724a5da91c136f
-BLACKFIRE_SERVER_ID=1171e53b-459b-41da-a292-80ff68cee8c2
-BLACKFIRE_SERVER_TOKEN=dbd1cfbea015fe83cccfc189a36ca3c16f3a1b43b94f50032a15e41e53548e8b
-###< BlackFire configuration ###
-
-###> AdminAssos configuration ###
-DATABASE_ADMINASSOS_URL=mysql://root:mysql2iopenservice369566@preprod:3306/adminassos?serverVersion=5.7
-###< AdminAssos configuration ###
-
-###> Audit configuration ###
-DATABASE_AUDIT_URL=mysql://root:mysql2iopenservice369566@preprod:3306/audit?serverVersion=5.7
-###< Audit configuration ###
-
-###> symfony/mercure-bundle ###
-# See https://symfony.com/doc/current/mercure.html#configuration
-# The URL of the Mercure hub, used by the app to publish updates (can be a local URL)
-MERCURE_URL=https://mercure.preprod.opentalent.fr/.well-known/mercure
-# The public URL of the Mercure hub, used by the browser to connect
-MERCURE_PUBLIC_URL=https://mercure.preprod.opentalent.fr/.well-known/mercure
-# The secret used to sign the JWTs
-MERCURE_JWT_SECRET=NQEupdREijrfYvCmF2mnvZQFL9zLKDH9RCYter6tUWzjemPqzicffhc2fSf0yEmM
-###< symfony/mercure-bundle ###
-
-###> bindfile populate buffer file
-BIND_FILE_BUFFER_FILE=var/subdomain.txt
-###< bindfile populate buffer file
-
-###> knplabs/knp-snappy-bundle ###
-WKHTMLTOPDF_PATH=/usr/bin/wkhtmltopdf
-WKHTMLTOIMAGE_PATH=/usr/bin/wkhtmltoimage
-###< knplabs/knp-snappy-bundle ###
-
-###> filename log ###
-LOG_FILE_NAME=preprod
-###< filename log ###

+ 16 - 0
.env.staging

@@ -0,0 +1,16 @@
+# Fichier d'env utilisé pour les tests fonctionnels et applicatifs
+APP_DEBUG=1
+APP_ENV=dev
+
+###> doctrine/doctrine-bundle ###
+DATABASE_URL=mysql://root:mysql660@db:3306/opentalent_test?serverVersion=5.7
+###< doctrine/doctrine-bundle ###
+
+###> api v1 ###
+API_LEG_BASE_URL=none
+###< api v1 ###
+
+###> elasticsearch ###
+ELASTICSEARCH_HOST=es
+ELASTICSEARCH_PORT=9200
+###< elasticsearch ###

+ 3 - 1
composer.json

@@ -69,6 +69,7 @@
     "require-dev": {
         "cyclonedx/cyclonedx-php-composer": "^3.4",
         "dg/bypass-finals": "^1.4",
+        "doctrine/doctrine-fixtures-bundle": "^3.4",
         "hautelook/alice-bundle": "^2.11",
         "phpstan/extension-installer": "^1.2",
         "phpstan/phpstan": "^1.9",
@@ -84,7 +85,8 @@
         "symfony/phpunit-bridge": "^6.2",
         "symfony/stopwatch": "6.2.*",
         "symfony/web-profiler-bundle": "6.2.*",
-        "timeweb/phpstan-enum": "^3.1"
+        "timeweb/phpstan-enum": "^3.1",
+        "zenstruck/foundry": "^1.31"
     },
     "config": {
         "optimize-autoloader": true,

+ 8 - 6
config/bundles.php

@@ -3,7 +3,7 @@
 return [
     Symfony\Bundle\FrameworkBundle\FrameworkBundle::class => ['all' => true],
     Symfony\Bundle\TwigBundle\TwigBundle::class => ['all' => true],
-    Symfony\Bundle\WebProfilerBundle\WebProfilerBundle::class => ['docker' => true, 'test' => true],
+    Symfony\Bundle\WebProfilerBundle\WebProfilerBundle::class => ['dev' => true, 'docker' => true, 'staging' => true],
     Symfony\Bundle\SecurityBundle\SecurityBundle::class => ['all' => true],
     Doctrine\Bundle\DoctrineBundle\DoctrineBundle::class => ['all' => true],
     Doctrine\Bundle\MigrationsBundle\DoctrineMigrationsBundle::class => ['all' => true],
@@ -12,15 +12,17 @@ return [
     Jb\Bundle\PhumborBundle\JbPhumborBundle::class => ['all' => true],
     Misd\PhoneNumberBundle\MisdPhoneNumberBundle::class => ['all' => true],
     Lexik\Bundle\JWTAuthenticationBundle\LexikJWTAuthenticationBundle::class => ['all' => true],
-    Symfony\Bundle\MakerBundle\MakerBundle::class => ['docker' => true],
+    Symfony\Bundle\MakerBundle\MakerBundle::class => ['dev' => true, 'docker' => true, 'staging' => true],
     FOS\ElasticaBundle\FOSElasticaBundle::class => ['all' => true],
     Knp\Bundle\SnappyBundle\KnpSnappyBundle::class => ['all' => true],
     Knp\Bundle\GaufretteBundle\KnpGaufretteBundle::class => ['all' => true],
     Symfony\Bundle\MonologBundle\MonologBundle::class => ['all' => true],
-    Symfony\Bundle\DebugBundle\DebugBundle::class => ['docker' => true],
+    Symfony\Bundle\DebugBundle\DebugBundle::class => ['dev' => true, 'docker' => true, 'staging' => true],
     Symfony\Bundle\MercureBundle\MercureBundle::class => ['all' => true],
     Twig\Extra\TwigExtraBundle\TwigExtraBundle::class => ['all' => true],
-    Nelmio\Alice\Bridge\Symfony\NelmioAliceBundle::class => ['dev' => true, 'test' => true],
-    Fidry\AliceDataFixtures\Bridge\Symfony\FidryAliceDataFixturesBundle::class => ['dev' => true, 'test' => true],
-    Hautelook\AliceBundle\HautelookAliceBundle::class => ['dev' => true, 'test' => true],
+    Nelmio\Alice\Bridge\Symfony\NelmioAliceBundle::class => ['dev' => true, 'staging' => true],
+    Fidry\AliceDataFixtures\Bridge\Symfony\FidryAliceDataFixturesBundle::class => ['staging' => true],
+    Hautelook\AliceBundle\HautelookAliceBundle::class => ['staging' => true],
+    Doctrine\Bundle\FixturesBundle\DoctrineFixturesBundle::class => ['staging' => true],
+    Zenstruck\Foundry\ZenstruckFoundryBundle::class => ['staging' => true],
 ];

+ 2 - 0
config/packages/doctrine.yaml

@@ -9,6 +9,7 @@ doctrine:
                 # IMPORTANT: You MUST configure your server version,
                 # either here or in the DATABASE_URL env var (see .env file)
                 server_version: '5.7'
+                schema_filter: ~^(?!view_)~
 
             audit:
                 url: '%env(resolve:DATABASE_AUDIT_URL)%'
@@ -23,6 +24,7 @@ doctrine:
         types:
             uuid: Ramsey\Uuid\Doctrine\UuidType
 
+
     orm:
         default_entity_manager: default
         auto_generate_proxy_classes: true

+ 7 - 0
config/packages/zenstruck_foundry.yaml

@@ -0,0 +1,7 @@
+when@dev: &dev
+    # See full configuration: https://symfony.com/bundles/ZenstruckFoundryBundle/current/index.html#full-default-bundle-configuration
+    zenstruck_foundry:
+        # Whether to auto-refresh proxies by default (https://symfony.com/bundles/ZenstruckFoundryBundle/current/index.html#auto-refresh)
+        auto_refresh_proxies: true
+
+when@test: *dev

+ 0 - 0
fixtures/.gitignore


تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 8167 - 0
sql/opentalent_test.sql


+ 7 - 0
sql/readme.md

@@ -0,0 +1,7 @@
+# SQL
+
+Pour regénérer le SQL de création de la DB vide :
+
+    mysqldump --user=root --password=mysql660 --host=localhost --port=3306 --default-character-set=utf8 --single-transaction=TRUE --no-data --skip-triggers "opentalent" --column-statistics=0 > opentalent_test.sql
+
+    mysql --user=root --password=mysql660 --host=127.0.0.1 --port=3306 -D opentalent_test < opentalent_test.sql

+ 29 - 0
src/DataFixtures/AppFixtures.php

@@ -0,0 +1,29 @@
+<?php
+
+namespace App\DataFixtures;
+
+use App\Entity\Organization\Organization;
+use App\Entity\Organization\Parameters;
+use App\Enum\Organization\LegalEnum;
+use App\Enum\Organization\PrincipalTypeEnum;
+use Doctrine\Bundle\FixturesBundle\Fixture;
+use Doctrine\Persistence\ObjectManager;
+use App\Entity\Booking\Event;
+
+class AppFixtures extends Fixture
+{
+    public function load(ObjectManager $em): void
+    {
+        $parameters = new Parameters();
+        $em->persist($parameters);
+
+        $organization = new Organization();
+        $organization->setName('Organization 1');
+        $organization->setLegalStatus(LegalEnum::ASSOCIATION_LAW_1901()->getValue());
+        $organization->setPrincipalType(PrincipalTypeEnum::ARTISTIC_EDUCATION_ONLY()->getValue());
+        $organization->setParameters($parameters);
+        $em->persist($organization);
+
+        $em->flush();
+    }
+}

+ 1 - 1
src/Entity/Billing/AbstractBillingIntangible.php

@@ -22,7 +22,7 @@ use Doctrine\Common\Collections\Collection;
     'access' => 'AccessIntangible',
     'educationalproject' => 'EducationalProjectIntangible'
 ])]
-abstract class AbstractBillingIntangible{
+abstract class AbstractBillingIntangible {
     #[ORM\Id]
     #[ORM\Column]
     #[ORM\GeneratedValue]

+ 3 - 3
src/Entity/Billing/EducationalProjectIntangible.php

@@ -14,12 +14,12 @@ use Doctrine\ORM\Mapping as ORM;
  */
 //#[Auditable]
 #[ORM\Entity]
-class EducationalProjectIntangible
+class EducationalProjectIntangible extends AbstractBillingIntangible
 {
     #[ORM\Id]
     #[ORM\Column]
     #[ORM\GeneratedValue]
-    private ?int $id = null;
+    protected ?int $id = null;
 
     #[ORM\ManyToOne(inversedBy: 'educationalProjectIntangibles')]
     private EducationalProject $educationalProject;
@@ -78,4 +78,4 @@ class EducationalProjectIntangible
 
         return $this;
     }
-}
+}

+ 248 - 0
src/Entity/Core/AbstractInformation.php

@@ -0,0 +1,248 @@
+<?php
+declare (strict_types=1);
+
+
+namespace App\Entity\Core;
+
+use ApiPlatform\Metadata\GetCollection;
+use ApiPlatform\Metadata\Get;
+use ApiPlatform\Metadata\ApiResource;
+use App\Entity\Access\Access;
+use App\Entity\Organization\Organization;
+use App\Repository\Core\NotificationRepository;
+
+//use DH\Auditor\Provider\Doctrine\Auditing\Annotation\Auditable;
+use Doctrine\Common\Collections\ArrayCollection;
+use Doctrine\Common\Collections\Collection;
+use Doctrine\ORM\Mapping as ORM;
+use JetBrains\PhpStorm\Pure;
+use Symfony\Component\Validator\Constraints as Assert;
+use App\Enum\Core\NotificationTypeEnum;
+use Symfony\Component\Serializer\Normalizer\DateTimeNormalizer;
+use Symfony\Component\Serializer\Annotation\Context;
+
+/**
+ * @todo : A la suite de la migration, il faut supprimer le nom de la table pour avoir une table Notification, et supprimer l'attribut discr.
+ *
+ * Classe Notification. qui permet de gérer les notifications aux utilisateurs.
+ */
+#[ApiResource(
+    operations: [
+        new Get(),
+        new GetCollection(
+            paginationMaximumItemsPerPage: 20,
+            paginationClientItemsPerPage: true,
+            order: ['id' => 'DESC']
+        )
+    ]
+)]
+//#[Auditable]
+#[ORM\Entity]
+#[ORM\Table(name: 'Information')]
+#[ORM\InheritanceType('SINGLE_TABLE')]
+#[ORM\DiscriminatorColumn(name: 'discr', type: 'string')]
+#[ORM\DiscriminatorMap([
+    'notification' => 'Notification',
+    'tips' => 'Tips'
+])]
+class AbstractInformation
+{
+    #[ORM\Id]
+    #[ORM\Column]
+    #[ORM\GeneratedValue]
+    private ?int $id = null;
+
+    #[ORM\ManyToOne(inversedBy: 'notifications')]
+    #[ORM\JoinColumn(nullable: false)]
+    private ?Access $recipientAccess;
+
+    #[ORM\ManyToOne(inversedBy: 'notifications')]
+    #[ORM\JoinColumn(nullable: false)]
+    private ?Organization $recipientOrganization;
+
+    #[ORM\Column(length: 40, nullable: true)]
+    private ?string $name = null;
+
+    #[ORM\Column(type: 'datetime', nullable: true)]
+    private ?\DateTimeInterface $createDate;
+
+    #[ORM\Column(type: 'datetime', nullable: true)]
+    private ?\DateTimeInterface $updateDate;
+
+    #[ORM\Column(type: 'json', length: 4294967295, nullable: true)]
+    private mixed $message = [];
+
+    #[ORM\Column(nullable: true)]
+    #[Assert\Choice(callback: [NotificationTypeEnum::class, 'toArray'], message: 'invalid-type')]
+    private ?string $type = null;
+
+    #[ORM\Column(length: 255, nullable: true)]
+    private ?string $link = null;
+
+    #[ORM\Column(type: 'date', nullable: true)]
+    #[Context(normalizationContext: [DateTimeNormalizer::FORMAT_KEY => 'Y-m-d'])]
+    private ?\DateTimeInterface $availabilityDate = null;
+
+    #[ORM\OneToMany(mappedBy: 'notification', targetEntity: NotificationUser::class, cascade: ['persist'], orphanRemoval: true)]
+    private Collection $notificationUsers;
+
+    #[Pure]
+    public function __construct()
+    {
+        $this->notificationUsers = new ArrayCollection();
+    }
+
+    public function getId(): ?int
+    {
+        return $this->id;
+    }
+
+    public function setName(?string $name): self
+    {
+        $this->name = $name;
+        return $this;
+    }
+
+    public function getName(): ?string
+    {
+        return $this->name;
+    }
+
+    public function setRecipientAccess(?Access $recipientAccess): self
+    {
+        $this->recipientAccess = $recipientAccess;
+        return $this;
+    }
+
+    public function getRecipientAccess(): ?Access
+    {
+        return $this->recipientAccess;
+    }
+
+    /**
+     * @return Organization|null
+     */
+    public function getRecipientOrganization(): ?Organization
+    {
+        return $this->recipientOrganization;
+    }
+
+    /**
+     * @param Organization|null $recipientOrganization
+     * @return Notification
+     */
+    public function setRecipientOrganization(?Organization $recipientOrganization): AbstractInformation
+    {
+        $this->recipientOrganization = $recipientOrganization;
+        return $this;
+    }
+
+    /**
+     * @return \DateTimeInterface|null
+     */
+    public function getCreateDate(): ?\DateTimeInterface
+    {
+        return $this->createDate;
+    }
+
+    /**
+     * @param \DateTimeInterface|null $createDate
+     */
+    public function setCreateDate(?\DateTimeInterface $createDate): self
+    {
+        $this->createDate = $createDate;
+        return $this;
+    }
+
+    /**
+     * @return \DateTimeInterface|null
+     */
+    public function getUpdateDate(): ?\DateTimeInterface
+    {
+        return $this->updateDate;
+    }
+
+    /**
+     * @param \DateTimeInterface|null $updateDate
+     */
+    public function setUpdateDate(?\DateTimeInterface $updateDate): self
+    {
+        $this->updateDate = $updateDate;
+        return $this;
+    }
+
+    public function setMessage(mixed $message): self
+    {
+        $this->message = $message;
+        return $this;
+    }
+
+    public function getMessage(): mixed
+    {
+        if (!is_array($this->message)) {
+            return ['about' => $this->message];
+        }
+        return $this->message;
+    }
+
+    public function setType(?string $type): self
+    {
+        $this->type = $type;
+        return $this;
+    }
+
+    public function getType(): ?string
+    {
+        return $this->type;
+    }
+
+    public function setLink(?string $link): self
+    {
+        $this->link = $link;
+        return $this;
+    }
+
+    public function getLink(): ?string
+    {
+        return $this->link;
+    }
+
+    public function getAvailabilityDate(): ?\DateTimeInterface
+    {
+        return $this->availabilityDate;
+    }
+
+    public function setAvailabilityDate(?\DateTime $availabilityDate = null): self
+    {
+        if ($availabilityDate == null) {
+            $availabilityDate = new \DateTime();
+        }
+        $this->availabilityDate = $availabilityDate;
+        return $this;
+    }
+
+    public function getNotificationUsers(): Collection
+    {
+        return $this->notificationUsers;
+    }
+
+    public function addNotificationUser(NotificationUser $notificationUsers): self
+    {
+        if (!$this->notificationUsers->contains($notificationUsers)) {
+            $this->notificationUsers[] = $notificationUsers;
+            $notificationUsers->setNotification($this);
+        }
+        return $this;
+    }
+
+    public function removeNotificationUser(NotificationUser $notificationUsers): self
+    {
+        if ($this->notificationUsers->removeElement($notificationUsers)) {
+            // set the owning side to null (unless already changed)
+            if ($notificationUsers->getNotification() === $this) {
+                $notificationUsers->setNotification(null);
+            }
+        }
+        return $this;
+    }
+}

+ 1 - 16
src/Entity/Core/Notification.php

@@ -38,17 +38,13 @@ use Symfony\Component\Serializer\Annotation\Context;
 )]
 //#[Auditable]
 #[ORM\Entity(repositoryClass: NotificationRepository::class)]
-#[ORM\Table(name: 'Information')]
-class Notification
+class Notification extends AbstractInformation
 {
     #[ORM\Id]
     #[ORM\Column]
     #[ORM\GeneratedValue]
     private ?int $id = null;
 
-    #[ORM\Column(length: 255, nullable: false)]
-    private string $discr = 'notification';
-
     #[ORM\ManyToOne(inversedBy: 'notifications')]
     #[ORM\JoinColumn(nullable: false)]
     private ?Access $recipientAccess;
@@ -242,15 +238,4 @@ class Notification
         }
         return $this;
     }
-
-    public function getDiscr(): ?string
-    {
-        return $this->discr;
-    }
-
-    public function setDiscr(string $discr): self
-    {
-        $this->discr = $discr;
-        return $this;
-    }
 }

+ 17 - 2
src/Entity/Core/Tips.php

@@ -4,14 +4,29 @@ declare(strict_types=1);
 namespace App\Entity\Core;
 
 //use DH\Auditor\Provider\Doctrine\Auditing\Annotation\Auditable;
+use ApiPlatform\Metadata\ApiResource;
+use ApiPlatform\Metadata\Get;
+use ApiPlatform\Metadata\GetCollection;
+use App\Repository\Core\NotificationRepository;
 use Doctrine\ORM\Mapping as ORM;
 
 /**
  * Classe ... qui ...
  */
 //#[Auditable]
+#[ApiResource(
+    operations: [
+        new Get(),
+        new GetCollection(
+            paginationMaximumItemsPerPage: 20,
+            paginationClientItemsPerPage: true,
+            order: ['id' => 'DESC']
+        )
+    ]
+)]
+//#[Auditable]
 #[ORM\Entity]
-class Tips
+class Tips extends AbstractInformation
 {
     #[ORM\Id]
     #[ORM\Column]
@@ -22,4 +37,4 @@ class Tips
     {
         return $this->id;
     }
-}
+}

+ 2 - 1
src/Entity/Organization/Organization.php

@@ -209,7 +209,8 @@ class Organization
     private ?string $ffecApproval = null;
 
     #[ORM\Column]
-    private bool $portailVisibility;
+    private bool $portailVisibility = true;
+
     #[ORM\Column(nullable: true)]
     private ?int $cmsId = null;
 

+ 2 - 2
src/Entity/Organization/Parameters.php

@@ -147,9 +147,9 @@ class Parameters
     #[Assert\Choice(callback: ['\\App\\Enum\\Core\\TimeZoneEnum', 'toArray'], message: 'invalid-timezone')]
     private ?string $timezone = "Europe/Paris";
 
-    #[ORM\Column(length: 255, nullable: true, options: ['default' => 'ANNUAL'])]
+    #[ORM\Column(length: 255, nullable: false, options: ['default' => 'ANNUAL'])]
     #[Assert\Choice(callback: ['\\App\\Enum\\Education\\PeriodicityEnum', 'toArray'], message: 'invalid-periodicity')]
-    private ?string $educationPeriodicity = null;
+    private ?string $educationPeriodicity = 'ANNUAL';
 
     #[ORM\Column(length: 255, nullable: true, options: ['default' => 'BY_EDUCATION'])]
     #[Assert\Choice(callback: ['\\App\\Enum\\Education\\AdvancedEducationNotationTypeEnum', 'toArray'], message: 'invalid-advanced-education-notation-type')]

+ 7 - 15
src/Entity/Place/Place.php

@@ -35,11 +35,14 @@ use Doctrine\ORM\Mapping as ORM;
 //#[Auditable]
 #[ORM\Entity]
 #[ORM\Table(name: 'Place')]
+#[ORM\InheritanceType('SINGLE_TABLE')]
+#[ORM\DiscriminatorColumn(name: 'discr', type: 'string')]
+#[ORM\DiscriminatorMap([
+    'place' => 'Place',
+    'place_system' => 'PlaceSystem'
+])]
 class Place
 {
-    #[ORM\Column(length: 255, nullable: false)]
-    private string $discr = 'place';
-
     #[ORM\Id]
     #[ORM\Column]
     #[ORM\GeneratedValue]
@@ -106,17 +109,6 @@ class Place
         $this->equipmentUseds = new ArrayCollection();
     }
 
-    public function getDiscr(): ?string
-    {
-        return $this->discr;
-    }
-
-    public function setDiscr(string $discr): self
-    {
-        $this->discr = $discr;
-        return $this;
-    }
-
     public function getId(): ?int
     {
         return $this->id;
@@ -439,4 +431,4 @@ class Place
         }
         return $this;
     }
-}
+}

+ 15 - 5
tests/Application/OtWebTestCase.php

@@ -4,20 +4,30 @@ namespace App\Tests\Application;
 
 use Symfony\Component\HttpFoundation\Request;
 use Symfony\Component\DomCrawler\Crawler;
+use \Symfony\Bundle\FrameworkBundle\KernelBrowser;
+use \Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
 
-class OtWebTestCase extends \Symfony\Bundle\FrameworkBundle\Test\WebTestCase
+/**
+ * Base class for applicative tests
+ */
+abstract class OtWebTestCase extends WebTestCase
 {
-    protected \Symfony\Bundle\FrameworkBundle\KernelBrowser $client;
+    protected KernelBrowser $client;
 
     public function setup(): void {
-        self::ensureKernelShutdown();
         $this->client = static::createClient();
     }
 
-    protected function get(string $route): Crawler {
+    /**
+     * @param string $route
+     * @param array<mixed> $parameters
+     * @return Crawler
+     */
+    protected function get(string $route, array $parameters = []): Crawler {
         return $this->client->request(
             Request::METHOD_GET,
-            $route
+            $route,
+            $parameters
         );
     }
 }

برخی فایل ها در این مقایسه diff نمایش داده نمی شوند زیرا تعداد فایل ها بسیار زیاد است