Symfony'de Controller yerine Action sınıfını kullanın
Ben yapışık am Eylem Sınıf kullanmak yerine yaklaşımı Kontrolörü . Açıklama çok basittir: Denetleyici çok sayıda eylem içerir, Bağımlılık Ekleme ilkesini takip ederken gerekli tüm bağımlılıkları bir kurucuya aktarmamız gerekir ve bu, Denetleyicinin çok sayıda bağımlılığa sahip olduğu, ancak belirli bir zamanda bir durum yaratır . (örneğin istek) sadece bazı bağımlılıkları kullanıyoruz. Bu spagetti kodunu sürdürmek ve test etmek zor.
Açıklığa kavuşturmak için, Zend Framework 2'de zaten bu yaklaşımla çalışıyordum, ancak burada Middleware olarak adlandırılıyor . API-Platform'da, Controller yerine Action sınıfını da kullandıkları benzer bir şey buldum , ancak sorun şu ki, onu nasıl pişireceğimi bilmiyorum.
UPD: Bir sonraki Eylem Sınıfını nasıl edinebilirim ve standart Denetleyiciyi nasıl değiştirebilirim ve normal Symfony projesine hangi yapılandırmayı eklemeliyim?
<?php
declare(strict_types=1);
namespace App\Action\Product;
use App\Entity\Product;
use Doctrine\ORM\EntityManager;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Method;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
class SoftDeleteAction
{
/**
* @var EntityManager
*/
private $entityManager; /** * @param EntityManager $entityManager
*/
public function __construct(EntityManager $entityManager) { $this->entityManager = $entityManager; } /** * @Route( * name="app_product_delete", * path="products/{id}/delete" * ) * * @Method("DELETE") * * @param Product $product
*
* @return Response
*/
public function __invoke(Request $request, $id): Response
{
$product = $this->entityManager->find(Product::class, $id); $product->delete();
$this->entityManager->flush();
return new Response('', 204);
}
}
Yanıtlar
Soru stackoverflow için biraz belirsiz olsa da biraz ilginç. İşte bazı yapılandırma ayrıntıları.
Kullanıma hazır S4 iskelet projesiyle başlayın:
symfony new --version=lts s4api
cd s4api
bin/console --version # 4.4.11
composer require orm-pack
SoftDeleteAction'ı ekleyin
namespace App\Action\Product;
class SoftDeleteAction
{
private $entityManager; public function __construct(EntityManagerInterface $entityManager)
{
$this->entityManager = $entityManager;
}
public function __invoke(Request $request, int $id) : Response
{
return new Response('Product ' . $id);
}
}
Ve rotayı tanımlayın:
# config/routes.yaml
app_product_delete:
path: /products/{id}/delete
controller: App\Action\Product\SoftDeleteAction
Bu noktada kablolama neredeyse tamamlanmıştır. URL'ye giderseniz:
The controller for URI "/products/42/delete" is not callable:
Bunun nedeni, hizmetlerin varsayılan olarak özel olmasıdır. Normalde, hizmeti herkese açık hale getirmekle ilgilenen AbstractController'dan uzanırsınız, ancak bu durumda en hızlı yaklaşım, eylemi bir denetleyici olarak etiketlemektir:
# config/services.yaml
App\Action\Product\SoftDeleteAction:
tags: ['controller.service_arguments']
Bu noktada, çalışan bir kablolu eyleminiz olmalıdır.
Elbette birçok varyasyon ve birkaç ayrıntı daha var. Rotayı POST veya sahte SİLME ile sınırlandırmak isteyeceksiniz.
Ayrıca, boş bir ControllerServiceArgumentsInterface eklemeyi ve ardından denetleyici hizmetlerini artık manuel olarak tanımlamanıza gerek kalmaması için denetleyici etiketini uygulamak için hizmetler örnek işlevini kullanmayı da düşünebilirsiniz.
Ancak bu, başlamanız için yeterli olmalıdır.
Uygulamaya çalıştığım yaklaşım ADR kalıbı (Action-Domain-Responseder) olarak adlandırıldı ve Symfony bunu zaten 3.3 sürümünden başlattı. Buna Invokable Controllers olarak başvurabilirsiniz .
Resmi belgelerden:
Denetleyiciler ayrıca, ADR modelini (Eylem-Etki Alanı-Yanıtlayıcı) izlerken yaygın bir uygulama olan __invoke () yöntemini kullanarak tek bir eylem tanımlayabilir:
// src/Controller/Hello.php
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
/**
* @Route("/hello/{name}", name="hello")
*/
class Hello
{
public function __invoke($name = 'World') { return new Response(sprintf('Hello %s!', $name));
}
}