Puncte:1

Returnează o închidere de la o fabrică

drapel cn

Am servicii care depind de informații solicitate. Încerc să creez un Fabrica Fabrica care va avea containerul Dependency Injection returnează o fabrică (o funcție anonimă) care va crea serviciile pe care le doresc. Deci practic ceva de genul asta:

clasa FooFactoryFactory {
  funcția publică statică create(ContainerInterface $container): apelabil {
     returnează funcția statică (Solicitare $cerere) folosește ($container) {
       $raz = cerere->get('param_raz');
       returnează barul nou (
           $container->get(LoggerInterface::class),
           $raz,
       );
     };
  }

}

Problema pe care o am este că Închidere este creat corect, dar clasa Dependency Injection Container de Drupal încearcă să seteze o proprietate pentru Închidere. Acest lucru nu poate funcționa și se termină cu o eroare fatală:

Obiectul de închidere nu poate avea proprietăți

Iată locul unde apare:

// Drupal\Component\DependencyInjection\Container::createService() - Linia 283-293
if (isset($definiție['proprietăți'])) {
  if ($definition['properties'] instanceof \stdClass) {
    $definition['properties'] = $this->resolveServicesAndParameters($definition['properties']);
  }
  foreach ($definition['properties'] as $key => $value) {
     $serviciu->{$cheie} = $valoare; // <-- Nu va funcționa pentru Închidere
  }
}
...

Deci intrebarile pe care le am:

  • Este asta prin design? Înseamnă că este ceva ce nu este dorit în ceea ce privește practica de codificare?
  • Eroarea poate fi evitată dacă reușesc să mă asigur că serviciul pe care vreau să-l creez nu are proprietăți este definiția. Pur și simplu nu știu cum să realizez asta.

Mulțumesc pentru ajutor în această chestiune.

EDITAȚI | ×: Acesta este, practic, ceea ce încerc să obțin:


  service.închidere.fabrică:
    clasa: Drupal\some_module\ClosureFactoryService
  closure.service:
    clasa: Închidere
    fabrică: [ '@closure.factory.service', getCallable ]
clasa ClosureFactoryService {
  funcția publică getCallable(): Închidere {
    returnează funcția statică (int $arg): șir {
      return sprintf('val %d', $arg);
    };
  }
}

Eu iau: Obiectul de închidere nu poate avea proprietăți în Drupal\Component\DependencyInjection\Container->createService() (linia 288...

4uk4 avatar
drapel cn
Dacă serviciul dvs. depinde de informațiile solicitate, atunci injectați `@request_stack` Pentru a înțelege designul dvs., puteți furniza întregul cod, în special clasa Bar și definiția serviciului care provoacă eroarea. De ce utilizați această metodă specifică din fabrică? Puteți oferi mai mult context?
drapel cn
Tocmai am editat întrebarea pentru a avea codul original ca în `Drupal\Component\DependencyInjection\Container.php`. @4k4: cam așa este în exemplu. Serviciile de care vreau să am dependențe să fie extrase din container și depind de container. Este ceva ce nu este permis să fie implementat în acest fel?
apaderno avatar
drapel us
În Drupal, serviciile sunt definite într-un fișier .services.yml, ceea ce @4k4 a cerut să vadă. De asemenea, un serviciu definit în acel fișier nu implementează nicio metodă `create()`. Dependency Injection folosită de Drupal, care este Symfony Dependency Injection, se așteaptă ca `create()` să returneze o instanță a acelei clase, nu o închidere.
drapel cn
Bună @apaderno, mulțumesc pentru răspuns. Nu am menționat declarația de servicii în fișierele `*.yml` pentru că nu am probleme. Provocarea pe care o am este să returnez o funcție anonimă (de fabrică) din următoarea clasă Drupal `Drupal\Component\DependencyInjection\Container.php`.Am postat fragmentul de cod în acea clasă care o face să eșueze. `Closure` este creat corect în clasa Drupal menționată, dar următoarele rânduri fac ca `Container.php` să arate o eroare. Voi verifica implementarea containerului Symfony.
apaderno avatar
drapel us
Aceste informații sunt necesare; cel puțin, este necesar să înțelegem dacă acea clasă este pentru un serviciu definit în fișierul .services.yml al modulului. În acest fel, răspunsul poate fi mai util.
Puncte:4
drapel us

În Drupal, clasa pentru un serviciu definit într-un fișier modul .services.yml nu trebuie să fie implementată create(ContainerInterface $container). Nici măcar nu se solicită implementarea unei interfețe PHP specifice.

Vedeți unul dintre serviciile implementate de bază Drupal, de exemplu path_alias.manager serviciu.

path_alias.manager:
  clasa: Drupal\path_alias\AliasManager
  argumente:
   - „@path_alias.repository”
   - „@path_alias.whitelist”
   - „@language_manager”
   - „@cache.data”

The AliasManager clasa care implementează acel serviciu nu implementează niciunul crea() metodă; doar implementează constructor, cu parametrii definiți în aceeași ordine sunt listate argumentele serviciului.

funcția publică __construct($alias_repository, AliasWhitelistInterface $whitelist, LanguageManagerInterface $language_manager, CacheBackendInterface $cache) {
  $this->pathAliasRepository = $alias_repository;
  $this->languageManager = $language_manager;
  $this->whitelist = $listă albă;
  $this->cache = $cache;
}

Clasele care implementează create(ContainerInterface $container) și care implementează ContainerInjectionInterface, de exemplu cel CronForm clasă, nu returnați o închidere de la create(ContainerInterface $container); ei returnează de fapt doar o instanță a lor. Vedea CronForm::create().

funcția publică statică create(ContainerInterface $container) {
  returnează static nou ($container->get('config.factory'),
    $container->get('state'),
    $container->get('cron'),
    $container->get('data.formatter'),
    $container->get('module_handler')
  );
}

Dacă doriți să implementați un serviciu din fabrică în Drupal, ar trebui să luați cache_factory serviciu ca exemplu pentru a vă scrie codul.

cache_factory:
  clasa: Drupal\Core\Cache\CacheFactory
  argumente:
    - „@settings”
    - „%cache_default_bin_backends%”
  apeleaza:
    - [setContainer, ['@service_container']]

Un serviciu care folosește acel serviciu ca fabrică este, de exemplu, the cache.render serviciu.

cache.render:
  clasa: Drupal\Core\Cache\CacheBackendInterface
  Etichete:
    - { nume: cache.bin }
  fabrică:
    - „@cache_factory”
    - obține
  argumente:
    - reda

The fabrică cheia definește care serviciu este serviciul din fabrică și ce metodă este apelată pentru acel serviciu din fabrică; cel argumente cheia definește argumentele transmise acelei metode. În acest caz, îi spune lui Drupal să instanțieze cache.render serviciu prin instanțierea cache_factory service și apelare obtine('renda') pe acel obiect.

drapel cn
Multumesc pentru raspunsul detaliat. Mi-am editat întrebarea pentru a imagina ceea ce încerc să obțin. Cred că nu se poate cu actualul Container Drupal. Sau fac ceva greșit.
Jaypan avatar
drapel de
Nu ați furnizat cazul de utilizare a ceea ce încercați să faceți (sau problema pe care încercați să o remediați/evitați), ci doar problemele pe care le aveți în încercarea de a o implementa. Bănuiesc că vă luați experiența anterioară în PHP și încercați să o aplicați pentru a face ceva care este gestionat într-un mod diferit folosind cadrul Drupal. Poate ați putea explica mai multe despre cazul dvs. de utilizare, mai degrabă decât despre implementarea dvs. Altfel, este greu de spus dacă o faci „greșit” (alias – într-o manieră non-Drupally) sau nu.
apaderno avatar
drapel us
@Jaypan iau că dickwan este pur și simplu obișnuit cu modul în care funcționează DI cu diferite biblioteci/cadre.De exemplu, în PHP-DI este perfect să aveți o fabrică de servicii implementată cu un obiect `Closure` (sau orice obiect apelabil), dar același lucru nu este valabil în Drupal.
apaderno avatar
drapel us
@dickwan După cum ați aflat, Drupal se așteaptă să poată adăuga proprietăți obiectului returnat pentru un serviciu. Deoarece obiectele „Închidere” nu pot avea proprietăți, acestea nu pot fi utilizate. Ceea ce am descris în răspuns este modul Drupal de a implementa un service și o fabrică de service. Rețineți că instanțele unei clase care implementează [`__invoke()`](https://www.php.net/manual/en/language.oop5.magic.php#object.invoke) sunt obiecte apelabile, pentru PHP și pot avea proprietăți, ceea ce se așteaptă Drupal. Dacă `$callable` este unul dintre aceste obiecte, `$result = $callable();` este un cod perfect valid.
drapel cn
@apaderno: Mulțumesc. Într-adevăr, am fost puțin surprins că abordarea pe care am vrut să o iau nu funcționa. Cred că am căutat motivul din spatele acestui comportament specific cadrului. Deci, consider că Framework-ul se comportă așa cum era de așteptat și probabil că nu este posibil să creați un serviciu fără proprietăți
apaderno avatar
drapel us
@dickwan Drupal folosește componente Symfony, dar nu se comportă ca Symfony în toate cazurile.Știind că Drupal folosește Symfony poate ajuta la înțelegerea modului în care funcționează Drupal, dar este totuși necesar să ne uităm la codul Drupal, pentru a înțelege Drupal complet.

Postează un răspuns

Majoritatea oamenilor nu înțeleg că a pune multe întrebări deblochează învățarea și îmbunătățește legătura interpersonală. În studiile lui Alison, de exemplu, deși oamenii își puteau aminti cu exactitate câte întrebări au fost puse în conversațiile lor, ei nu au intuit legătura dintre întrebări și apreciere. În patru studii, în care participanții au fost implicați în conversații ei înșiși sau au citit transcrieri ale conversațiilor altora, oamenii au avut tendința să nu realizeze că întrebarea ar influența – sau ar fi influențat – nivelul de prietenie dintre conversatori.