Score:1

ส่งคืนการปิดจากโรงงาน

ธง cn

ฉันมีบริการที่ขึ้นอยู่กับคำขอข้อมูล ฉันกำลังพยายามสร้างไฟล์ โรงงาน โรงงาน ซึ่งจะมีคอนเทนเนอร์ Dependency Injection ส่งคืนโรงงาน (ฟังก์ชันนิรนาม) ที่จะสร้างบริการที่ฉันต้องการ โดยพื้นฐานแล้วจะเป็นดังนี้:

คลาส FooFactoryFactory {
  สร้างฟังก์ชั่นสแตติกสาธารณะ (ContainerInterface $container): เรียกได้ {
     ส่งคืนฟังก์ชันคงที่ (ขอ $request) ใช้ ($container) {
       $raz = request->get('param_raz');
       คืนบาร์ใหม่(
           $container->get(LoggerInterface::class),
           $ ราซ
       );
     };
  }

}

ปัญหาที่ฉันมีก็คือว่า ปิด ถูกสร้างขึ้นอย่างถูกต้อง แต่คลาส Dependency Injection Container ของ de Drupal พยายามตั้งค่าคุณสมบัติเป็น ปิด. ไม่สามารถใช้งานได้และจบลงด้วยข้อผิดพลาดร้ายแรง:

วัตถุปิดไม่สามารถมีคุณสมบัติได้

นี่คือสถานที่ที่เกิดขึ้น:

// Drupal\Component\DependencyInjection\Container::createService() - บรรทัดที่ 283-293
ถ้า (isset($definition['properties'])) {
  ถ้า ($definition['properties'] อินสแตนซ์ของ \stdClass) {
    $definition['properties'] = $this->resolveServicesAndParameters($definition['properties']);
  }
  foreach ($definition['properties'] เป็น $key => $value) {
     $service->{$key} = $value; // <-- จะใช้ไม่ได้กับการปิด
  }
}
...

ดังนั้นคำถามที่ฉันมี:

  • นี่คือการออกแบบหรือไม่? หมายความว่าเป็นสิ่งที่ไม่ต้องการในแง่ของการฝึกเขียนโค้ดหรือไม่?
  • ข้อผิดพลาดสามารถหลีกเลี่ยงได้หากฉันจัดการเพื่อให้แน่ใจว่าไม่มีบริการที่ฉันต้องการสร้าง คุณสมบัติ มันเป็นคำจำกัดความ ฉันแค่ไม่รู้ว่าจะบรรลุสิ่งนี้ได้อย่างไร

ขอบคุณสำหรับความช่วยเหลือในเรื่องนี้

แก้ไข: นี่คือสิ่งที่ฉันพยายามจะบรรลุ:


  ปิดโรงงานบริการ:
    คลาส: Drupal\some_module\ClosureFactoryService
  ปิดบริการ:
    ชั้น: ปิด
    โรงงาน: [ '@close.factory.service', getCallable ]
คลาส ClosureFactoryService {
  ฟังก์ชั่นสาธารณะ getCallable (): ปิด {
    ส่งคืนฟังก์ชันคงที่ (int $arg): สตริง {
      ส่งคืน sprintf('val %d', $arg);
    };
  }
}

ฉันเข้าใจ: วัตถุปิดไม่สามารถมีคุณสมบัติใน Drupal\Component\DependencyInjection\Container->createService() (บรรทัดที่ 288...

4uk4 avatar
cn flag
หากบริการของคุณขึ้นอยู่กับข้อมูลคำขอ ให้ใส่ `@request_stack` เพื่อทำความเข้าใจการออกแบบของคุณ คุณสามารถระบุโค้ดทั้งหมด โดยเฉพาะคลาส Bar และคำจำกัดความของบริการที่ทำให้เกิดข้อผิดพลาดได้หรือไม่ เหตุใดคุณจึงใช้วิธีเฉพาะของโรงงานนี้ คุณสามารถให้บริบทเพิ่มเติมได้หรือไม่
cn flag
ฉันเพิ่งแก้ไขคำถามเป็น Have the orignal code as in `Drupal\Component\DependencyInjection\Container.php` @ 4k4: นั่นค่อนข้างมากในตัวอย่าง บริการที่ฉันต้องการต้องมีการดึงการอ้างอิงจากคอนเทนเนอร์และขึ้นอยู่กับคอนเทนเนอร์ เป็นสิ่งที่ไม่ได้รับอนุญาตให้ดำเนินการเช่นนั้นหรือไม่?
apaderno avatar
us flag
ใน Drupal บริการถูกกำหนดไว้ในไฟล์ .services.yml ซึ่งเป็นสิ่งที่ @4k4 ขอดู นอกจากนี้ บริการที่กำหนดในไฟล์นั้นไม่ได้ใช้วิธี `create()` ใดๆ การพึ่งพาการแทรกที่ใช้โดย Drupal ซึ่งเป็น Symfony Dependency Injection คาดว่า `create()` จะส่งคืนอินสแตนซ์ของคลาสนั้น ไม่ใช่การปิด
cn flag
สวัสดี @apaderno ขอบคุณสำหรับการตอบกลับ ฉันไม่ได้กล่าวถึงการประกาศบริการในไฟล์ `*.yml` เพราะนั่นไม่ใช่จุดที่ฉันมีปัญหา ความท้าทายที่ฉันมีคือการส่งคืนฟังก์ชันนิรนาม (โรงงาน) จากคลาส `Drupal\Component\DependencyInject\Container.php` ของ Drupal ต่อไปนี้ฉันได้โพสต์รหัสในชั้นเรียนที่ทำให้ล้มเหลว `Closure` ถูกสร้างขึ้นอย่างถูกต้องในคลาส Drupal ที่กล่าวถึง แต่บรรทัดถัดไปทำให้ `Container.php` เกิดข้อผิดพลาด ฉันจะตรวจสอบการใช้งานคอนเทนเนอร์ของ Symfony
apaderno avatar
us flag
ข้อมูลนั้นจำเป็น อย่างน้อยที่สุด จำเป็นต้องเข้าใจว่าคลาสนั้นมีไว้สำหรับบริการที่กำหนดไว้ในไฟล์ .services.yml ของโมดูลหรือไม่ ด้วยวิธีนี้คำตอบจะมีประโยชน์มากขึ้น
Score:4
ธง us

ใน Drupal คลาสสำหรับบริการที่กำหนดในไฟล์ .services.yml ของโมดูลไม่จำเป็นต้องใช้ สร้าง (ContainerInterface $container). ไม่มีการร้องขอให้ใช้อินเทอร์เฟซ PHP เฉพาะ

ดูหนึ่งในบริการหลักที่ Drupal ใช้ เช่น path_alias.manager บริการ.

path_alias.manager:
  คลาส: Drupal\path_alias\AliasManager
  ข้อโต้แย้ง:
   - '@path_alias.repository'
   - '@path_alias.ไวท์ลิสต์'
   - '@language_manager'
   - '@cache.data'

เดอะ ผู้จัดการนามแฝง คลาสที่ใช้บริการนั้นไม่ได้ใช้งานใด ๆ สร้าง() กระบวนการ; มันเพียงแค่ใช้ ตัวสร้างด้วยพารามิเตอร์ที่กำหนดไว้ในลำดับเดียวกัน อาร์กิวเมนต์บริการจะแสดงรายการ

ฟังก์ชันสาธารณะ __construct($alias_repository, AliasWhitelistInterface $รายการที่อนุญาต, LanguageManagerInterface $language_manager, CacheBackendInterface $cache) {
  $this->pathAliasRepository = $alias_repository;
  $this->languageManager = $language_manager;
  $this->รายการที่อนุญาต = $รายการที่อนุญาต;
  $this->cache = $แคช;
}

คลาสที่ใช้ สร้าง (ContainerInterface $container) และการดำเนินการใด อินเตอร์เฟสคอนเทนเนอร์อินเจคชั่นตัวอย่างเช่น ครอนฟอร์ม ชั้นไม่กลับปิดจาก สร้าง (ContainerInterface $container); พวกเขากลับคืนตัวอย่างของตัวเองเท่านั้น ดู CronForm::create().

สร้างฟังก์ชันคงที่สาธารณะ (ContainerInterface $container) {
  ส่งคืนค่าคงที่ใหม่ ($container->get('config.factory'),
    $container->get('สถานะ'),
    $container->get('cron'),
    $container->get('date.formatter'),
    $container->get('module_handler')
  );
}

หากคุณต้องการใช้บริการโรงงานใน Drupal คุณควรใช้ cache_factory บริการเป็นตัวอย่างในการเขียนโค้ดของคุณ

cache_factory:
  คลาส: Drupal\Core\Cache\CacheFactory
  ข้อโต้แย้ง:
    - '@การตั้งค่า'
    - '%cache_default_bin_backends%'
  โทร:
    - [setContainer, ['@service_container']]

บริการที่ใช้บริการนั้นเป็นโรงงาน เช่น cache.render บริการ.

cache.render:
  คลาส: Drupal\Core\Cache\CacheBackendInterface
  แท็ก:
    - { ชื่อ: cache.bin }
  โรงงาน:
    - '@cache_factory'
    - รับ
  ข้อโต้แย้ง:
    - เรนเดอร์

เดอะ โรงงาน คีย์กำหนดว่าบริการใดเป็นบริการจากโรงงานและวิธีการใดที่เรียกใช้สำหรับบริการโรงงานนั้น เดอะ ข้อโต้แย้ง คีย์กำหนดอาร์กิวเมนต์ที่ส่งไปยังเมธอดนั้น ในกรณีนี้ เป็นการบอก Drupal ให้สร้างอินสแตนซ์ของ cache.render บริการโดยยกตัวอย่างของ cache_factory บริการและการโทร รับ ('แสดงผล') บนวัตถุนั้น

cn flag
ขอบคุณสำหรับคำตอบโดยละเอียด ฉันได้แก้ไขคำถามของฉันเพื่อให้เห็นภาพสิ่งที่ฉันพยายามจะบรรลุ ฉันคิดว่ามันเป็นไปไม่ได้กับ Drupal Container ปัจจุบัน หรือฉันทำอะไรผิดไปมาก
Jaypan avatar
de flag
คุณไม่ได้ให้กรณีการใช้งานของสิ่งที่คุณพยายามทำ (หรือปัญหาที่คุณพยายามแก้ไข/หลีกเลี่ยง) เฉพาะปัญหาที่คุณมีในการพยายามนำไปใช้ ฉันสงสัยว่าคุณกำลังใช้ประสบการณ์ PHP ก่อนหน้านี้ และพยายามใช้มันเพื่อทำบางสิ่งที่มีการจัดการในลักษณะที่แตกต่างออกไปโดยใช้เฟรมเวิร์ก Drupal บางทีคุณอาจอธิบายเพิ่มเติมเกี่ยวกับกรณีการใช้งานของคุณ มากกว่าการนำไปปฏิบัติ มิฉะนั้นก็ยากที่จะบอกว่าคุณกำลังทำ "ผิด" (หรือที่เรียกอีกอย่างว่า - ในลักษณะที่ไม่ใช่ Drupally) หรือไม่
apaderno avatar
us flag
@Jaypan ฉันใช้ dickwan ง่ายๆ ว่า DI ทำงานกับไลบรารี่/กรอบงานต่างๆ ได้อย่างไรตัวอย่างเช่น ใน PHP-DI นั้นดีอย่างยิ่งที่จะให้โรงงานบริการดำเนินการกับวัตถุ `ปิด` (หรือวัตถุที่เรียกได้) แต่สิ่งเดียวกันนั้นใช้ไม่ได้ใน Drupal
apaderno avatar
us flag
@dickwan อย่างที่คุณทราบ Drupal คาดว่าจะสามารถเพิ่มคุณสมบัติให้กับวัตถุที่ส่งคืนสำหรับบริการ เนื่องจากวัตถุ `ปิด` ไม่สามารถมีคุณสมบัติได้ จึงไม่สามารถใช้งานได้ สิ่งที่ฉันอธิบายในคำตอบคือวิธี Drupal ในการใช้บริการและโรงงานบริการ โปรดทราบว่าอินสแตนซ์ของคลาสที่ใช้ [`__invoke()`](https://www.php.net/manual/en/language.oop5.magic.php#object.invoke) เป็นวัตถุที่เรียกได้ สำหรับ PHP และสามารถมีคุณสมบัติ ซึ่งเป็นสิ่งที่ Drupal คาดหวัง หาก `$callable` เป็นหนึ่งในอ็อบเจกต์เหล่านั้น `$result = $callable();` ก็เป็นรหัสที่ถูกต้องสมบูรณ์
cn flag
@apaderno: ขอบคุณ ฉันรู้สึกประหลาดใจเล็กน้อยที่วิธีที่ฉันต้องการใช้ไม่ได้ผล ฉันคิดว่าฉันกำลังมองหาเหตุผลที่ทำให้เกิดพฤติกรรมเฉพาะของเฟรมเวิร์กนี้ ดังนั้นฉันจึงถือว่า Framework ทำงานตามที่คาดไว้และอาจไม่สามารถสร้างบริการที่ไม่มีคุณสมบัติได้
apaderno avatar
us flag
@dickwan Drupal ใช้ส่วนประกอบของ Symfony แต่มันไม่ได้ทำงานเหมือน Symfony ในทุกกรณีการรู้ว่า Drupal ใช้ Symfony สามารถช่วยให้เข้าใจวิธีการทำงานของ Drupal แต่ก็ยังจำเป็นต้องดูโค้ด Drupal เพื่อทำความเข้าใจ Drupal อย่างครบถ้วน

โพสต์คำตอบ

คนส่วนใหญ่ไม่เข้าใจว่าการถามคำถามมากมายจะปลดล็อกการเรียนรู้และปรับปรุงความสัมพันธ์ระหว่างบุคคล ตัวอย่างเช่น ในการศึกษาของ Alison แม้ว่าผู้คนจะจำได้อย่างแม่นยำว่ามีคำถามกี่ข้อที่ถูกถามในการสนทนา แต่พวกเขาไม่เข้าใจความเชื่อมโยงระหว่างคำถามและความชอบ จากการศึกษาทั้ง 4 เรื่องที่ผู้เข้าร่วมมีส่วนร่วมในการสนทนาด้วยตนเองหรืออ่านบันทึกการสนทนาของผู้อื่น ผู้คนมักไม่ตระหนักว่าการถามคำถามจะมีอิทธิพลหรือมีอิทธิพลต่อระดับมิตรภาพระหว่างผู้สนทนา