Maison  >  Questions et réponses  >  le corps du texte

Shopware 6, classes abstraites et injection de dépendances dans Symfony

Actuellement je développe une extension Shopware 6 basée sur Symfony. Ce que je ne comprends pas, c'est comment implémenter des classes abstraites et l'injection de dépendances.

Je souhaite donc pouvoir refactoriser le code et utiliser ces méthodes souvent, mais dans un autre contexte (en utilisant un autre référentiel)

<?php

declare(strict_types=1);

namespace WShopService;

use ShopwareCoreFrameworkContext;
use ShopwareCoreFrameworkDataAbstractionLayerSearchCriteria;
use ShopwareCoreFrameworkDataAbstractionLayerEntityRepository;
use ShopwareCoreFrameworkDataAbstractionLayerSearchFilterEqualsFilter;
use ShopwareCoreFrameworkUuidUuid;

/**
 * Service for writing Products
 */
class ProductService
{
    private EntityRepository  $productRepository;
    private MediaImageService $mediaImageService;
    private EntityRepository  $productMediaRepository;

    public function __construct(
        EntityRepository  $productRepository,
        MediaImageService $mediaImageService,
        EntityRepository  $productMediaRepository
    )
    {
        $this->productRepository = $productRepository;
        $this->mediaImageService = $mediaImageService;
        $this->productMediaRepository = $productMediaRepository;
    }

private function createProduct(array $data, Context $context = null): void
{
    $context = $context ?? Context::createDefaultContext();

    $this->productRepository->create([
                                         $data
                                     ], $context);
}

public function updateProduct(array $data): void
{
    $this->productRepository->update([$data], Context::createDefaultContext());
}

public function getExistingProductId(string $productNumber): ?string
{
    $criteria = new Criteria();
    $criteria->addFilter(new EqualsFilter('productNumber', $productNumber));

    return $this->productRepository->searchIds($criteria, 
     Context::createDefaultContext())->firstId();
 }
}

Comme vous pouvez le voir, il y a une injection de dépendances à l'intérieur de la construction (référentiel produit). Maintenant, ma question est la suivante : comment puis-je créer une classe abstraite, c'est-à-dire stocker ces méthodes, mais la classe enfant « remplacera » la construction parent par le référentiel requis ? Par exemple, je souhaite utiliser la méthode getDataId (maintenant appelée getExistingProductId, mais sera refactorisée et renommée dans la classe abstraite) sur le Product Repository, mais pour la classe suivante, je souhaite utiliser la même chose sur la Category Méthodes du référentiel ?

Service.xml également connu sous le nom d'injecteur de dépendances

<service id="wshop_product_service" class="WShopServiceProductService">
            <argument type="service" id="product.repository"/>
            <argument id="wshop_media_image_service" type="service"/>
            <argument type="service" id="product_media.repository"/>
</service>

Je suis nouveau sur la POO. Veuillez fournir de bons exemples et des explications de code. Merci!

P粉680087550P粉680087550258 Il y a quelques jours446

répondre à tous(1)je répondrai

  • P粉248602298

    P粉2486022982024-01-10 00:03:24

    Si j'ai bien compris, vous voulez que seul le premier paramètre soit interchangeable, et les 3 méthodes de l'exemple doivent être implémentées dans l'abstraction. Voici une idée.

    Résumé :

    abstract class AbstractEntityService
    {
        protected EntityRepository $repository;
    
        public function __construct(EntityRepository  $repository)
        {
            $this->repository = $repository;
        }
    
        public function create(array $data, ?Context $context = null): void
        {
            $context = $context ?? Context::createDefaultContext();
    
            $this->repository->create([
                $data
            ], $context);
        }
    
        public function update(array $data): void
        {
            $this->repository->update([$data], Context::createDefaultContext());
        }
        
        abstract public function getDataId(array $params): ?string;
    
        protected function searchId(Criteria $criteria): ?string
        {
            return $this->repository->searchIds(
                $criteria,
                Context::createDefaultContext()
            )->firstId();
        }
    }
    

    Vous obtenez le référentiel dans le constructeur et implémentez toutes les méthodes courantes concernant le référentiel commun dans l'abstraction. getDataId méthodes que vous souhaitez implémenter dans votre classe étendue car vous utilisez des conditions spécifiques (vraisemblablement) pour chaque méthode. Il vous suffit donc de forcer l'implémentation dans la classe étendue en définissant une signature abstraite.

    Votre niveau de service :

    class ProductService extends AbstractEntityService
    {
        private MediaImageService $mediaImageService;
    
        private EntityRepository $productMediaRepository;
    
        public function __construct(
            EntityRepository $productRepository,
            MediaImageService $mediaImageService,
            EntityRepository $productMediaRepository
        ) {
            parent::__construct($productRepository);
            $this->mediaImageService = $mediaImageService;
            $this->productMediaRepository = $productMediaRepository;
        }
    
        public function getDataId(array $params): ?string
        {
            if (!isset($params['productNumber'])) {
                return null;
            }
    
            $criteria = new Criteria();
            $criteria->addFilter(new EqualsFilter('productNumber', $params['productNumber']));
    
            return $this->searchId($criteria);
        }
    
        // your other methods using the injected services
    }
    

    Dans la classe d'extension, vous transmettez uniquement le référentiel au constructeur parent car les autres services injectés ne sont utilisés que dans cette instance spécifique. Vous pouvez implémenter getDataId 并使用该条件调用受保护的(因为它只能由扩展使用)searchId où vous créez une condition spécifique et appelez la méthode protégée (car elle ne peut être utilisée que par les extensions) searchId avec cette condition.

    répondre
    0
  • Annulerrépondre