使用注入的实体存储库创建工厂
namespace App\DependencyInjection\Compiler;
use App\Factory\EntityFactoryRegistry;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Reference;
class EntityFactoryPass implements CompilerPassInterface
{
public function process(ContainerBuilder $container): void
{
if (!$container->has(EntityFactoryRegistry::class)) {
return;
}
$definition = $container->findDefinition(EntityFactoryRegistry::class);
$taggedServices = $container->findTaggedServiceIds('app.entity_factory');
$entityManager = $container->findDefinition('doctrine.orm.entity_manager');
foreach ($taggedServices as $id => $tags) {
$definition->addMethodCall('addFactory', [new Reference($id), $entityManager]);
}
}
}
//using code like this to get factory for entity, now this part works, I have the factory accessible everywhere I want.
foreach ((new \ReflectionClass($this::class))->getAttributes(Access::class) as $attribute) {
if (key_exists('entity', $attribute->getArguments())) {
$this->factory = $this->entityFactoryRegistry->get($attribute->getArguments()['entity']);
}
}
出厂后:
<?php
namespace App\Factory;
use App\Command\EntityCommandInterface;
use App\Command\PostCommand;
use App\Entity\Base\BaseEntity;
use App\Entity\Post;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\DependencyInjection\Attribute\Autoconfigure;
#[Autoconfigure(tags: ['app.entity_factory'])]
class PostFactory implements EntityFactoryInterface
{
private ?EntityManagerInterface $entityManager = null;
public function create(EntityCommandInterface|PostCommand $command): BaseEntity
{
}
public function edit(BaseEntity|Post $entity, EntityCommandInterface|PostCommand $command): BaseEntity
{
}
public function getMainPosts (): array
{
return $this->entityManager->getRepository($this->getEntity())
->findAll();
}
public function setEntityManager (EntityManagerInterface $entityManager): void
{
$this->entityManager = $entityManager;
}
public function getEntity(): string
{
return Post::class;
}
}
现在,当涉及到树枝扩展,我想得到工厂同样的方式,并通过它自定义树枝节点。
扩展创建:
namespace App\Extension;
use App\Extension\Parser\FactoryTokenParser;
use App\Factory\EntityFactoryRegistry;
use Twig\Extension\AbstractExtension;
class FactoryExtension extends AbstractExtension
{
public function __construct(
protected readonly EntityFactoryRegistry $entityFactoryRegistry,
)
{
}
public function getTokenParsers(): array
{
return [
new FactoryTokenParser($this->entityFactoryRegistry),
];
}
}
令牌解析器:
<?php
namespace App\Extension\Parser;
use App\Extension\Node\FactoryTagNode;
use App\Factory\EntityFactoryRegistry;
use Twig\Token;
use Twig\TokenParser\AbstractTokenParser;
class FactoryTokenParser extends AbstractTokenParser
{
public function __construct(
protected readonly EntityFactoryRegistry $entityFactoryRegistry,
)
{}
public function parse(Token $token): FactoryTagNode
{
$stream = $this->parser->getStream();
$entityClass = $this->parser->getExpressionParser()->parseExpression();
if (!class_exists($entityClass->getAttribute("value"))) {
throw new \Exception("Class provided to factory does not exist");
}
// Parse the content between {% factory %} and {% endfactory %}
$stream->expect(Token::BLOCK_END_TYPE);
$body = $this->parser->subparse([$this, 'decideFactoryEndTag'], true);
$stream->expect(Token::BLOCK_END_TYPE);
$entityFactory = $this->entityFactoryRegistry->get($entityClass->getAttribute("value"));
return new FactoryTagNode(
$entityFactory,
$body,
$token->getLine(),
$this->getTag()
);
}
public function decideFactoryEndTag(Token $token): bool
{
return $token->test('endfactory');
}
public function getTag(): string
{
return 'factory';
}
}
节点:
<?php
namespace App\Extension\Node;
use App\Factory\EntityFactoryInterface;
use Twig\Compiler;
use Twig\Node\Node;
class FactoryTagNode extends Node
{
private EntityFactoryInterface $factory;
public function __construct(EntityFactoryInterface $entityFactory, Node $body, int $line, string $tag)
{
parent::__construct(['body' => $body], [], $line, $tag);
$this->factory = $entityFactory;
}
public function compile(Compiler $compiler): void
{
$body = $this->getNode('body');
$compiler
->addDebugInfo($this)
->write(sprintf('$context["factory"] = %s;', $this->getVarExport($this->factory)))
->write('ob_start();' . PHP_EOL)
->subcompile($body)
->write('echo strtoupper(ob_get_clean());' . PHP_EOL);
}
private function getVarExport($var): ?string
{
return var_export($var, true);
}
}
现在是这部分,它不会工作。->write(sprintf('$context["factory"] = %s;', $this->getVarExport($this->factory)))
错误:在编译模板期间引发了异常(“警告:var_export不处理循环引用”)。
当我像这样初始化类->write(sprintf('$context["factory"] = new %s();', get_class(this->factory)))
时
Twig有可用的类,但我想注入工厂类,而不是为Twig重新初始化类的新示例。
为什么,原因是,实体管理器被注入到工厂使用编译器通行证,当我重新初始化类,它不再可用。
还有其他我无法解决的问题吗?
细枝渲染零件:
{% factory 'App\\Entity\\Post' %}
{{ dump(factory.mainPosts) }}
{% endfactory %}
1条答案
按热度按时间hzbexzde1#
好吧,我想明白了,基本上我是这么做的
FactoryExtension.php:
Main thing:FactoryTagNode.php:
和小枝: