web-dev-qa-db-ja.com

LogicException:コントローラの結果で、関連するキャッシュメタデータを提供していると主張されていますが、リークされたメタデータが検出されました

LogicException:コントローラーの結果は、関連するキャッシュメタデータを提供していると主張していますが、メタデータのリークが検出されました。コンテンツのレンダリングが早すぎないことを確認してください。返されるオブジェクトクラス:Drupal\rest\ResourceResponse。 Drupal\Core\EventSubscriber\EarlyRenderingControllerWrapperSubscriber-> wrapControllerExecutionInRenderContext()内(/ srv/bindings/8c5ccf24ccc9492bb85469725da608ea/code/core/lib/Drupal/Core/EventSubscriber/EarlyRenderingControllerWphpperSubscriberの154行目)。

REST ajax getリクエストを介してエンドポイントにアクセスしようとすると、この問題に直面しています。重要なのは、ログインしたときにすべての作品が見つかりましたが、上記の例外を通じてログインしていない場合です。

これが私のコードです

namespace Drupal\one_rest_api\Plugin\rest\resource;

use Drupal\file\Entity\File;
use Drupal\image\Entity\ImageStyle;
use Drupal\media_entity\Entity\Media;
use Drupal\node\Entity\Node;
use Drupal\rest\Plugin\ResourceBase;
use Drupal\rest\ResourceResponse;
use Drupal\Core\Session\AccountProxyInterface;
use Drupal\taxonomy\Entity\Term;
use Psr\Log\LoggerInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
use Symfony\Component\HttpKernel\Exception\HttpException;

/**
 * Provides article resource endpoint
 *
 * @RestResource(
 *   id = "one_article_resource",
 *   label = @Translation("One Article Resource"),
 *   uri_paths = {
 *     "canonical" = "/api/one/v1/articles"
 *   }
 * )
 */
class ArticleResource extends ResourceBase
{
    /**
     * A current user instance.
     *
     * @var \Drupal\Core\Session\AccountProxyInterface
     */
    protected $currentUser;

    /**
     * Constructs a Drupal\rest\Plugin\ResourceBase object.
     *
     * @param array $configuration
     *   A configuration array containing information about the plugin instance.
     * @param string $plugin_id
     *   The plugin_id for the plugin instance.
     * @param mixed $plugin_definition
     *   The plugin implementation definition.
     * @param array $serializer_formats
     *   The available serialization formats.
     * @param \Psr\Log\LoggerInterface $logger
     *   A logger instance.
     * @param \Drupal\Core\Session\AccountProxyInterface $current_user
     *   A current user instance.
     */
    public function __construct(
        array $configuration,
        $plugin_id,
        $plugin_definition,
        array $serializer_formats,
        LoggerInterface $logger,
        AccountProxyInterface $current_user) {

        parent::__construct($configuration, $plugin_id, $plugin_definition, $serializer_formats, $logger);

        $this->currentUser = $current_user;
    }

    /**
     * {@inheritdoc}
     */
    public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
        return new static(
            $configuration,
            $plugin_id,
            $plugin_definition,
            $container->getParameter('serializer.formats'),
            $container->get('logger.factory')->get('one_rest'),
            $container->get('current_user')
        );
    }
    /**
     * Responds to GET requests.
     *
     * Returns a list of bundles for specified entity.
     *
     * @throws \Symfony\Component\HttpKernel\Exception\HttpException
     *   Throws exception expected.
     */
    public function get() {
        global $base_url;

        $response_result = [];
        $response_code = 200;
        // You must to implement the logic of your REST Resource here.
        // Use current user after pass authentication to validate access.
        if (!$this->currentUser->hasPermission('access content')) {
            throw new AccessDeniedHttpException();
        }

        $entities = \Drupal::entityQuery('node')
            ->condition('status', 1)
            ->condition('type', 'article')
            ->condition('langcode','en')
            ->notExists('field_f1')
            ->sort('created', 'DESC')
            ->range(0, 20)
            ->execute();

        if(!empty($entities)){
            foreach ($entities as $node_id) {
                $node = Node::load($node_id);

                if(is_object($node)){
                    $image_url = '';
                    $image_target = $node->get('field_image')->target_id;
                    if(!empty($image_target)){
                        $media = Media::load($image_target);
                        if(is_object($media)){
                            $image = File::load($media->get('field_image')->target_id);
                            $image_url = ImageStyle::load('rest_api')->buildUrl($image->getFileUri());
                        }
                    }

                    $output_tags = [];
                    $tags = $node->get('field_tags')->getValue();
                    if(!empty($tags)){
                        foreach($tags as $key => $tag){
                            $term = Term::load($tag['target_id']);
                            $output_tags[] = $term->get('name')->value;
                        }
                    }

                    $result = [
                        "nid" => $node->id(),
                        "base_url" => $base_url,
                        "title" => $node->getTitle(),
                        "field_image" => $image_url,
                        "field_tags" => $output_tags
                    ];

                    $response_result[] = $result;
                }

            }
        }


        if(!empty($response_result)) {
            $headers = [
                'Access-Control-Allow-Origin' => '*',
                'Access-Control-Allow-Methods' => 'POST, GET, OPTIONS, PATCH, DELETE',
                'Access-Control-Allow-Headers' => 'Authorization'
            ];

            $response = new ResourceResponse($response_result, $response_code, $headers);
            return $response;
        }

        throw new HttpException(t("Empty Response"));
    }
}

そして以下は私のTypeScriptコードです

load(){

    if(this.data){
      return Promise.resolve(this.data);
    }

    return new Promise(resolve => {
      this.http.get('https://example.com/api/one/v1/articles?_format=json')
        .subscribe(data => {
          this.data = data;
          resolve(this.data);
        },err => {
          console.log(err);
        });
    });

  }

drupalコードに欠けているものを理解できませんでした

4
Udit Rawat

エンティティクエリを以下のように変更します

$entities = \Drupal::entityQuery('node')
            ->condition('status', 1)
            ->condition('type', 'article')
            ->condition('langcode','en')
            ->notExists('field_f1')
            ->sort('created', 'DESC')
            ->range(0, 20)
            ->accessCheck(false)   
            ->execute();
5
Raj Ghai

ResourceResponseクラスはメタデータのキャッシュを担当するCacheableResponseTraitを使用しているため、コードを最後に追加することで解決しました。 POST、PATCH、DELETEでは、リソースが変更されているため、これは望ましくありません。

return new ModifiedResourceResponse($node);

https://tutel.me/c/drupal/questions/249627/logicexception+node+save+via+resourcebase+post#

5
Ales

現在リストされている答えは、従うべき適切な方法だと思います。ただし、私はこれが適切であると思います。jsonapiモジュールをdrupal composerを使用して再インストールすることでこれを(おそらく一時的に)修正することができました。それが誰かを助けるかもしれない場合、これは私がコマンドラインから実行しました:

composer require 'drupal/jsonapi:^1.24'

インストールしようとしているバージョンにコードを変更することを忘れないでください。ご覧のとおり、これはバージョン1.24専用です。

1
G_Style