web-dev-qa-db-ja.com

カスタムAPIルーティングのキャッシュを正しく設定するにはどうすればよいですか?

JSONを返すいくつかのルート、たとえば語彙の用語を含むカスタムモジュールがあります。

routing.yml

mymodule.terms:
  path: '/api/terms/{vid}'
  defaults:
    _controller: '\Drupal\mymodule\Controller\MyModuleController::getTerms'
    _title: 'Terms'
  requirements:
    _permission: 'access content'
    vid: '^(foobar|barfoo)$'

コントローラ:

public function getTerms($vid) {
  $response = $this->jsonifyVocabulary($vid);
  return $response;
}

private function jsonifyVocabulary($vid) {
  $request = \Drupal::request();
  $lang = $request->query->get('lang', 'en');
  $output = [];
  $taxonomyManager = \Drupal::entityManager()->getStorage('taxonomy_term');
  $terms = $taxonomyManager->loadTree($vid, 0, 1, false);
  $response = CacheableJsonResponse::create($output);

  debug(1);

  foreach ($terms as $term) {
    $term = Term::load($term->tid);
    if ($term->hasTranslation($lang) && $lang !== $term->language()) {
      $term = $term->getTranslation($lang);
    }
    $entry = [
      'tid' => (int) $term->id(),
      'label' => $term->getName(),
    ];

    // $response->addCacheableDependency($term);
    $output[$vid][] = $entry;
  }

  $response->setData($output);

  $cacheMeta = (new CacheableMetadata())->addCacheContexts(['url.query_args:lang']);
  $response->addCacheableDependency($cacheMeta);

  return $response;
}

この回答のおかげで 実際にURLパラメータをキャッシュコンテキストとして追加する方法を知っていますが、

debug(1);

常に呼び出されます、私は何とかしてDrupalこのJSON応答のキャッシュがそのルートに関連している必要があることを伝えなければなりません...

コアのRESTモジュールを意図的に使用していません。必要なものを正確に出力するように構成することが難しいためです。

5
Alex

これは、応答のキャッシュを設定するために必要なすべてです。

  $response = CacheableJsonResponse::create($output);
  return $response;

CacheableResponseInterfaceを実装する応答を使用する場合、それは無期限にキャッシュされます。

キャッシュタグ

分類用語のリストを追加するときは、次のタグを追加する必要があります。

  $list_tags = $this->entityTypeManager()->getDefinition('taxonomy_term')->getListCacheTags();
  $cache_metadata->addCacheTags($list_tags);

  foreach ($terms as $term) {
    $cache_metadata->addCacheableDependency($term);
  }

これにより、データベースで用語が変更されると、キャッシュエントリが無効になります。

キャッシュコンテキスト

クエリパラメータを使用する場合は、次のコンテキストを追加します。

  $lang = $request->query->get('lang', 'en');
  $cache_metadata->addCacheContexts(['url.query_args:lang']);

これにより、クエリ引数によってキャッシュが変化します。

応答のキャッシュ可能なメタデータ

これらすべてを組み合わせるには、コントローラーの最初に空のCacheableMetadataオブジェクトを作成します。

  $cache_metadata = new CacheableMetadata();

コンテンツの構築中に、前の2つの例で説明したように、使用するすべての依存関係のキャッシュメタデータを収集し、コントローラーの最後で応答にメタデータを追加します。

$response->addCacheableDependency($cache_metadata);
9
4k4

..私は何とかしてDrupalこのjson応答のキャッシュがそのルートに関連している必要があることを伝えなければなりません...

「キャッシュコンテキスト」を見る ドキュメント 「デバッグ」の下:

"上記はすべて、キャッシュされているものをデバッグするときに役立つ情報です。しかし、もう1つあります。キャッシュキー['foo'、 'bar'でキャッシュされているものがあるとします。 ]とキャッシュコンテキスト['languages:language_interface'、 'user.permissions'、 'route']。次に、対応するキャッシュアイテムが特定のキャッシュビンにCID(キャッシュID)でキャッシュされます:

foo:bar:[languages:language_interface]=en:[user.permissions]=A_QUITE_LONG_HASH:[route]=myroute.ROUTE_PARAMS_HASH "

レスポンスでキャッシュコンテキストを定義している場合は、そのルートとキャッシュコンテキストのCIDを持つキャッシュビンにキャッシュする必要があります。

必要なものを正確に出力するように構成するのは難しいので、意図的にコアの残りのモジュールを使用しません。

DrupalコアRESTには、「分類学語彙」が含まれていますREST語彙IDを引数として取り込むリソース: enter image description here

デフォルトでは、次のような語彙の情報を返します。

{
  "uuid": "46fb0c72-4570-4c7f-b90d-faa69f2c5e7a",
  "langcode": "en",
  "status": true,
  "dependencies": [],
  "name": "Vocabulary Name",
  "vid": "vocabulary_vid",
  "description": "Some vocabulary description.",
  "hierarchy": 0,
  "weight": 0
}

ただし、特定の語彙の用語をJSON応答に表示するには、このRESTリソースの出力を好みに応じて変更できるカスタムノーマライザーを作成できます。

見る:

1
edwardchiapet

質問に対する回答がすでに見つかっているかどうかはわかりません。私は文字通り半日かけて何が問題なのかを見つけようとしました...まあ-答えは非常に簡単です。内部動的ページキャッシュモジュールが有効になっていることを確認してください。 (この最も簡単な方法:drush en -y dynamic_page_cache

モジュールが無効な場合、NOTHINGはキャッシュから取得されます。モジュール自体には、ルートの一致時にトリガーされるEventSubscriberがあります(dynamic_page_cache/src/EventSubscriber/DynamicPageCacheSubscriber.phpを参照):

/**
 * Sets a response in case of a Dynamic Page Cache hit.
 *
 * @param \Symfony\Component\HttpKernel\Event\GetResponseEvent $event
 *   The event to process.
 */
public function onRouteMatch(GetResponseEvent $event) {
  // Don't cache the response if the Dynamic Page Cache request policies are
  // not met. Store the result in a static keyed by current request, so that
  // onResponse() does not have to redo the request policy check.
  $request = $event->getRequest();
  $request_policy_result = $this->requestPolicy->check($request);
  $this->requestPolicyResults[$request] = $request_policy_result;
  if ($request_policy_result === RequestPolicyInterface::DENY) {
    return;
  }

  // Sets the response for the current route, if cached.
  $cached = $this->renderCache->get($this->dynamicPageCacheRedirectRenderArray);
  if ($cached) {
    $response = $this->renderArrayToResponse($cached);
    $response->headers->set(self::HEADER, 'HIT');
    $event->setResponse($response);
  }
}

これは実際にキャッシュ全体を処理し、キャッシュされたjson応答を返します。モジュールがないと、CachedJsonResponse全体が役に立たなくなります。

注:この回答は、ジェシュフ近くのモニカフロムザフォレストズ氏に全力で貢献したいと思います。この問題を見つけることへの彼女の献身とコミットメントが、チャレンジに取り組むこの素晴らしい機会を私に与えてくれました。ありがとうございました。神のお恵みがありますように。

1