无法生成自定义文档类型。

huangapple go评论83阅读模式
英文:

Shopware 6.5 - Cannot generate custom document type

问题

我理解你想要翻译的代码部分。以下是代码的中文翻译:

<?php declare(strict_types=1);

namespace Dima\OrderConfirmation\Core\Checkout\Document\Renderer;

use Shopware\Core\Checkout\Document\Renderer\AbstractDocumentRenderer;
use Shopware\Core\Checkout\Document\Renderer\DocumentRendererConfig;
use Shopware\Core\Checkout\Document\Renderer\RenderedDocument;
use Shopware\Core\Checkout\Document\Renderer\RendererResult;
use Shopware\Core\Checkout\Document\Service\DocumentConfigLoader;
use Shopware\Core\Checkout\Document\Struct\DocumentGenerateOperation;
use Shopware\Core\Checkout\Document\Twig\DocumentTemplateRenderer;
use Shopware\Core\Checkout\Order\OrderEntity;
use Shopware\Core\Defaults;
use Shopware\Core\Framework\Context;
use Shopware\Core\Framework\DataAbstractionLayer\EntityRepository;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Criteria;
use Shopware\Core\Framework\Plugin\Exception\DecorationPatternException;
use Shopware\Core\System\Locale\LocaleEntity;
use Shopware\Core\System\NumberRange\ValueGenerator\NumberRangeValueGeneratorInterface;

class OrderConfirmationRenderer extends AbstractDocumentRenderer
{
    public const DEFAULT_TEMPLATE = '@DimaOrderConfirmation/documents/order_confirmation.html.twig';

    final public const TYPE = 'order_confirmation';

    /**
     * @internal
     */
    public function __construct(
        private readonly EntityRepository $orderRepository,
        private readonly DocumentConfigLoader $documentConfigLoader,
        private readonly DocumentTemplateRenderer $documentTemplateRenderer,
        private readonly NumberRangeValueGeneratorInterface $numberRangeValueGenerator,
        private readonly string $rootDir,
    ) {
    }

    public function supports(): string
    {
        return self::TYPE;
    }

    /**
     * @param array<DocumentGenerateOperation> $operations
     */
    public function render(array $operations, Context $context, DocumentRendererConfig $rendererConfig): RendererResult
    {
        $ids = array_map(fn (DocumentGenerateOperation $operation) => $operation->getOrderId(), $operations);

        if (empty($ids)) {
            return new RendererResult();
        }

        $result = new RendererResult();

        $template = self::DEFAULT_TEMPLATE;

        $orders = $this->orderRepository->search(new Criteria($ids), $context)->getEntities();

        foreach ($orders as $order) {
            $orderId = $order->getId();

            try {
                $operation = $operations[$orderId] ?? null;
                if ($operation === null) {
                    continue;
                }

                $config = clone $this->documentConfigLoader->load(self::TYPE, $order->getSalesChannelId(), $context);

                $config->merge($operation->getConfig());

                $number = $config->getDocumentNumber() ?: $this->getNumber($context, $order, $operation);

                $now = (new \DateTime())->format(Defaults::STORAGE_DATE_TIME_FORMAT);

                $config->merge([
                    'documentDate' => $operation->getConfig()['documentDate'] ?? $now,
                    'documentNumber' => $number,
                    'custom' => [
                        'invoiceNumber' => $number,
                    ],
                ]);

                // If document is uploaded manually
                if ($operation->isStatic()) {
                    $doc = new RenderedDocument('', $number, $config->buildName(), $operation->getFileType(), $config->jsonSerialize());
                    $result->addSuccess($orderId, $doc);

                    continue;
                }

                /** @var LocaleEntity $locale */
                $locale = $order->getLanguage()->getLocale();

                $html = $this->documentTemplateRenderer->render(
                    $template,
                    [
                        'order' => $order,
                        'config' => $config,
                        'rootDir' => $this->rootDir,
                        'context' => $context,
                    ],
                    $context,
                    $order->getSalesChannelId(),
                    $order->getLanguageId(),
                    $locale->getCode()
                );

                $doc = new RenderedDocument(
                    $html,
                    $number,
                    $config->buildName(),
                    $operation->getFileType(),
                    $config->jsonSerialize(),
                );

                $result->addSuccess($orderId, $doc);
            } catch (\Throwable $exception) {
                $result->addError($orderId, $exception);
            }
        }

        return $result;
    }

    public function getDecorated(): AbstractDocumentRenderer
    {
        throw new DecorationPatternException(self::class);
    }

    private function getNumber(Context $context, OrderEntity $order, DocumentGenerateOperation $operation): string
    {
        return $this->numberRangeValueGenerator->getValue(
            'document_' . self::TYPE,
            $context,
            $order->getSalesChannelId(),
            $operation->isPreview()
        );
    }
}

希望这对你有所帮助。如果你有任何其他翻译需求,请随时告诉我。

英文:

I am currently trying to create a custom document type in Shopware 6.5.0.0 like described in the Shopware docs.

My custom document type gets recognized when i go to create a new document from an order in the admin, but when i try to generate the pdf - I get the error "Unable to find a document generator with type "order_confirmation"". As there is no example service created in the docs - i believe my error lies there. But i am not sure. I referenced the invoice service renderer registration for my services.xml

This is my services.xml:

&lt;container xmlns=&quot;http://symfony.com/schema/dic/services&quot;
xmlns:xsi=&quot;http://www.w3.org/2001/XMLSchema-instance&quot;
xsi:schemaLocation=&quot;http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd&quot;&gt;

    &lt;services&gt;
        &lt;service id=&quot;Dima\OrderConfirmation\Core\Checkout\Document\Renderer\OrderConfirmationRenderer&quot;&gt;
            &lt;argument type=&quot;service&quot; id=&quot;order.repository&quot;/&gt;
            &lt;argument type=&quot;service&quot; id=&quot;Shopware\Core\Checkout\Document\Service\DocumentConfigLoader&quot;/&gt;
            &lt;argument type=&quot;service&quot; id=&quot;Shopware\Core\Checkout\Document\Twig\DocumentTemplateRenderer&quot;/&gt;
            &lt;argument type=&quot;service&quot; id=&quot;Shopware\Core\System\NumberRange\ValueGenerator\NumberRangeValueGeneratorInterface&quot;/&gt;
            &lt;argument&gt;%kernel.project_dir%&lt;/argument&gt;
            
            &lt;tag name=&quot;document.renderer&quot; /&gt;
        &lt;/service&gt;
    &lt;/services&gt;
&lt;/container&gt;

And this is my document renderer:

&lt;?php declare(strict_types=1);

namespace Dima\OrderConfirmation\Core\Checkout\Document\Renderer;

use Shopware\Core\Checkout\Document\Renderer\AbstractDocumentRenderer;
use Shopware\Core\Checkout\Document\Renderer\DocumentRendererConfig;
use Shopware\Core\Checkout\Document\Renderer\RenderedDocument;
use Shopware\Core\Checkout\Document\Renderer\RendererResult;
use Shopware\Core\Checkout\Document\Service\DocumentConfigLoader;
use Shopware\Core\Checkout\Document\Struct\DocumentGenerateOperation;
use Shopware\Core\Checkout\Document\Twig\DocumentTemplateRenderer;
use Shopware\Core\Checkout\Order\OrderEntity;
use Shopware\Core\Defaults;
use Shopware\Core\Framework\Context;
use Shopware\Core\Framework\DataAbstractionLayer\EntityRepository;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Criteria;
use Shopware\Core\Framework\Plugin\Exception\DecorationPatternException;
use Shopware\Core\System\Locale\LocaleEntity;
use Shopware\Core\System\NumberRange\ValueGenerator\NumberRangeValueGeneratorInterface;

class OrderConfirmationRenderer extends AbstractDocumentRenderer
{
    public const DEFAULT_TEMPLATE = &#39;@DimaOrderConfirmation/documents/order_confirmation.html.twig&#39;;

    final public const TYPE = &#39;order_confirmation&#39;;

    /**
     * @internal
     */
    public function __construct(
        private readonly EntityRepository $orderRepository,
        private readonly DocumentConfigLoader $documentConfigLoader,
        private readonly DocumentTemplateRenderer $documentTemplateRenderer,
        private readonly NumberRangeValueGeneratorInterface $numberRangeValueGenerator,
        private readonly string $rootDir,
    ) {
    }

    public function supports(): string
    {
        return self::TYPE;
    }

    /**
     * @param array&lt;DocumentGenerateOperation&gt; $operations
     */
    public function render(array $operations, Context $context, DocumentRendererConfig $rendererConfig): RendererResult
    {
        $ids = \array_map(fn (DocumentGenerateOperation $operation) =&gt; $operation-&gt;getOrderId(), $operations);

        if (empty($ids)) {
            return new RendererResult();
        }

        $result = new RendererResult();

        $template = self::DEFAULT_TEMPLATE;

        $orders = $this-&gt;orderRepository-&gt;search(new Criteria($ids), $context)-&gt;getEntities();

        foreach ($orders as $order) {
            $orderId = $order-&gt;getId();

            try {
                $operation = $operations[$orderId] ?? null;
                if ($operation === null) {
                    continue;
                }

                $config = clone $this-&gt;documentConfigLoader-&gt;load(self::TYPE, $order-&gt;getSalesChannelId(), $context);

                $config-&gt;merge($operation-&gt;getConfig());

                $number = $config-&gt;getDocumentNumber() ?: $this-&gt;getNumber($context, $order, $operation);

                $now = (new \DateTime())-&gt;format(Defaults::STORAGE_DATE_TIME_FORMAT);

                $config-&gt;merge([
                    &#39;documentDate&#39; =&gt; $operation-&gt;getConfig()[&#39;documentDate&#39;] ?? $now,
                    &#39;documentNumber&#39; =&gt; $number,
                    &#39;custom&#39; =&gt; [
                        &#39;invoiceNumber&#39; =&gt; $number,
                    ],
                ]);

                // If document is uploaded manually
                if ($operation-&gt;isStatic()) {
                    $doc = new RenderedDocument(&#39;&#39;, $number, $config-&gt;buildName(), $operation-&gt;getFileType(), $config-&gt;jsonSerialize());
                    $result-&gt;addSuccess($orderId, $doc);

                    continue;
                }

                /** @var LocaleEntity $locale */
                $locale = $order-&gt;getLanguage()-&gt;getLocale();

                $html = $this-&gt;documentTemplateRenderer-&gt;render(
                    $template,
                    [
                        &#39;order&#39; =&gt; $order,
                        &#39;config&#39; =&gt; $config,
                        &#39;rootDir&#39; =&gt; $this-&gt;rootDir,
                        &#39;context&#39; =&gt; $context,
                    ],
                    $context,
                    $order-&gt;getSalesChannelId(),
                    $order-&gt;getLanguageId(),
                    $locale-&gt;getCode()
                );

                $doc = new RenderedDocument(
                    $html,
                    $number,
                    $config-&gt;buildName(),
                    $operation-&gt;getFileType(),
                    $config-&gt;jsonSerialize(),
                );

                $result-&gt;addSuccess($orderId, $doc);
            } catch (\Throwable $exception) {
                $result-&gt;addError($orderId, $exception);
            }
        }

        return $result;
    }

    public function getDecorated(): AbstractDocumentRenderer
    {
        throw new DecorationPatternException(self::class);
    }

    private function getNumber(Context $context, OrderEntity $order, DocumentGenerateOperation $operation): string
    {
        return $this-&gt;numberRangeValueGenerator-&gt;getValue(
            &#39;document_&#39; . self::TYPE,
            $context,
            $order-&gt;getSalesChannelId(),
            $operation-&gt;isPreview()
        );
    }
}

I confirmed that the TYPE const matches with the document type i create in my migration, as i first thought that there maybe was a typo - but to no success.

What is it that i'm missing here?

答案1

得分: 0

这一切看起来都是正确的。你是否像这样实现了supports方法?

public function supports(): string
{
    return self::TYPE;
}

这是唯一会引发异常的行。而且只会在遍历所有标记为document.renderer的服务并且没有评估支持该类型的服务时发生异常。

看起来你的服务如果没有匹配到的话根本就没有被注册。你是否有其他在services.xml中注册的服务,以确认它们已经注册了,这样你就可以确定你没有错放文件之类的事情?

英文:

That all looks to be correct. Did you implement the supports method like this?

public function supports(): string
{
    return self::TYPE;
}

This is the only line where this exception is thrown. And it only happens if it iterates all the document.renderer tagged services without evaluating one that supports the type.

It looks like your service is not being registered at all if it's not matching up. Do you have other services in your services.xml that you can confirm being registered, so you can say for sure you didn't misplace the file or something like that?

huangapple
  • 本文由 发表于 2023年6月15日 16:30:55
  • 转载请务必保留本文链接:https://go.coder-hub.com/76480588.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定