Cách chính xác để đặt bối cảnh bộ đệm trên các khối tùy chỉnh là gì?


13

Tôi đã gặp phải một vấn đề trong đó một khối duy nhất trên mỗi trang không dành cho người dùng đã đăng xuất. Vấn đề là một plugin khối tùy chỉnh tôi có trên trang tìm kiếm lượt xem có chứa các bộ lọc tùy chỉnh (giống như một thay thế tùy chỉnh cho các bộ lọc bị lộ. Khối được đặt qua / admin / architecture / block).

Dựa trên những gì tôi đã học được về Drupal 8, tôi đã thêm bối cảnh bộ đệm vào mảng xây dựng của mình:

  public function build() {

    $search_form = \Drupal::formBuilder()->getForm('Drupal\mymodule\Form\SearchForm');
    return [
      'search_form' => $search_form,
      '#cache' => ['contexts' => ['url.path', 'url.query_args']]
    ];

  }

Nhưng có vẻ như điều này không chính xác vì khi đăng xuất, khối sẽ được lưu vào bộ đệm ở chế độ xem đầu tiên và khi url thay đổi, nó không hiển thị phiên bản mới của khối.

Tôi nghĩ rằng nó có thể là trang xem gây ra sự cố, nhưng ngay cả khi tôi tắt bộ nhớ đệm trên trang xem, vấn đề vẫn còn.

Tôi đã có thể khắc phục sự cố theo một số cách, ví dụ, bằng cách sử dụng hook pre process_block:

function mymodule_preprocess_block__mycustomsearchblock(&$variables) {
  $variables['#cache']['contexts'][] = 'url.path';
  $variables['#cache']['contexts'][] = 'url.query_args';
}

Nhưng điều đó làm phiền tôi, tôi không thể đặt bối cảnh bộ đệm vào mảng xây dựng của khối.

Vì khối của tôi mở rộng BlockBase, tôi đã quyết định thử phương thức getCacheContexts (), đặc biệt khi tôi thấy một số mô-đun trong lõi đang thực hiện theo cách này.

  public function getCacheContexts() {
    return Cache::mergeContexts(parent::getCacheContexts(), ['url.path', 'url.query_args']);
  }

Điều này cũng đã được khắc phục sự cố, nhưng thật thú vị, khi tôi xuất các biến trong hàm khối tiền xử lý, chúng không hiển thị trong các biến $ ['# cache'] ['bối cảnh'], nhưng chúng hiển thị trong các phần tử $ biến [' '] [' # cache '] [' bối cảnh ']

array:5 [▼
  0 => "languages:language_interface"
  1 => "theme"
  2 => "url.path"
  3 => "url.query_args"
  4 => "user.permissions"
]

Tôi đang cố gắng tìm hiểu làm thế nào điều này hoạt động, và tại sao nó không hoạt động từ chức năng xây dựng.

Nhìn vào /core/modules/block/src/BlockViewBuilder.php tại hàm viewMult Môn (), có vẻ như nó kéo các thẻ bộ đệm từ thực thể và plugin:

'contexts' => Cache::mergeContexts(
  $entity->getCacheContexts(),
  $plugin->getCacheContexts()
),

Vì vậy, điều đó giải thích tại sao việc thêm phương thức getCacheContexts () vào plugin khối của tôi lại thêm bối cảnh vào khối của tôi. Ngoài ra, nhìn vào phương thức preRender trong cùng một lớp, có vẻ như nó không sử dụng mảng bộ đệm trong hàm xây dựng khối, điều này làm tôi bối rối, vì có vẻ như cách thêm bộ đệm vào Drupal 8 là thêm #cache yếu tố để kết xuất các yếu tố.

Vì vậy, câu hỏi của tôi là,

1) Các bối cảnh bộ đệm được thêm trực tiếp vào mảng trong một plugin khối bị bỏ qua?

2) Nếu vậy, có cách nào khác không, chúng ta có cần thêm nó vào một phần tử con của mảng xây dựng không?

3) Nếu bối cảnh được thêm trực tiếp bị bỏ qua, việc thêm getCacheContexts () có phải là cách để bổ sung khối trong các mô-đun tùy chỉnh không?


1
1) Không, nội dung khối của bạn thực sự là một mức giảm và nên được hợp nhất sau này. 2) Không cần thiết vì 1, 3) Việc triển khai getCacheContexts () có thể dễ dàng / sạch hơn nhưng không cần thiết. Bạn đề cập rõ ràng đến người dùng ẩn danh, bạn có chắc chắn rằng điều đó cũng không ảnh hưởng đến người dùng được xác thực thông thường không? Sự cố có biến mất nếu bạn tắt Dynamic_page_cache không? Một cái gì đó kỳ lạ phải xảy ra nếu nó chỉ ảnh hưởng đến người dùng anon, vì bộ đệm trang bên trong luôn thay đổi theo url / truy vấn đối số.
Berdir

1
Vô hiệu hóa bộ đệm trang động không khắc phục vấn đề.
oknate

1
Hừm, có thể có vấn đề với thực tế là phần tử cấp cao nhất của bạn không chứa bất cứ thứ gì ngoại trừ #cache. Bạn đã cố gắng chỉ đơn giản là đặt #cache trong mẫu của mình chưa? Đó là hình thức cần thay đổi theo những cái đó, và vì các thẻ bộ nhớ cache nổi lên, nên nó chỉ hoạt động. Và nếu bạn từng sử dụng biểu mẫu của mình ở một khối khác hoặc một nơi khác, thì nó cũng sẽ hoạt động ở đó.
Berdir

1
Tôi đã nhanh chóng hack SyndicateBlock và sử dụng phương thức build () này: gist.github.com/Berdir/33a31b1e98caf080dae78adb731dba4c . Đặt rằng trên trang web của tôi hoạt động tốt, bối cảnh bộ đệm được hiển thị trong bảng cache numnder và URI yêu cầu chính xác được hiển thị. Bạn có thể thử tương tự? Dường như với tôi như có điều gì đó rất kỳ lạ đang diễn ra trên trang web của bạn
Berdir

2
Bạn có sử dụng mẫu khối tiêu chuẩn hoặc một mẫu tùy chỉnh không? Xem drupal.stackexchange.com/questions/217884/ từ
4k4

Câu trả lời:


9

Trong hầu hết các trường hợp, bạn chỉ cần đặt bối cảnh bộ đệm trực tiếp trên mảng kết xuất mà bạn trả về trong phương thức build ().

Cuối cùng tôi đã tìm thấy vấn đề của mình là gì, với sự giúp đỡ của @Berdir và @ 4k4. Nếu bạn đang sử dụng một mẫu tùy chỉnh, chẳng hạn như khối - myblock.html.twig và bạn xuất các biến riêng lẻ, chẳng hạn như {{content.foo}} thay vì tất cả cùng một lúc như {{content}}, nó sẽ bỏ qua bối cảnh bộ nhớ cache của bạn được truyền trực tiếp vào mảng xây dựng khối của bạn, khi đăng xuất. Xem cách chính xác để đặt bối cảnh bộ đệm trên các khối tùy chỉnh là gì?

Vì vậy, để trả lời câu hỏi ban đầu:

1) Các bối cảnh bộ nhớ cache được truyền trực tiếp vào một plugin khối tùy chỉnh đôi khi bị bỏ qua. Bạn có thể kiểm tra điều này bằng cách thay đổi SyndicateBlock , sau đó tạo mẫu tùy chỉnh trong khối chủ đề của bạn - syndicate.html.php trong đó bạn xuất các biến như thế này:

{% block content %}
  {{ content.foo }}
{% endblock %}

Khi bạn thay đổi đối số url, bạn sẽ thấy khối không tôn trọng bối cảnh bộ đệm.

Bây giờ nếu bạn thay đổi nó xuất ra tất cả nội dung dưới dạng một mảnh, nó hoạt động:

{% block content %}
  {{ content }}
{% endblock %}

Bây giờ, nó tôn trọng bối cảnh bộ đệm và khối là duy nhất trên mỗi trang.

2) Hiện tại, để giải quyết vấn đề này, bạn chỉ có thể xuất những gì trong khối của mình trong mẫu của chính nó.

 public function build() {

    $search_form = \Drupal::formBuilder()->getForm('Drupal\mymodule\Form\SearchForm');
    return [
      '#theme' => 'mycustomtemplate',
      '#search_form' => $search_form,
      '#cache' => ['contexts' => ['url.path', 'url.query_args']]
    ];

  }

Điều này phá vỡ các ngoại lệ bộ nhớ đệm bí mật của mô-đun khối và biểu mẫu của bạn hiện là duy nhất trên mỗi trang khi đăng xuất.

3) Bạn có nên tạo mẫu chủ đề của riêng mình để khắc phục điều này hay chỉ cần thêm một phương thức cho getCacheContexts () trong plugin Chặn tùy chỉnh của bạn? Tốt hơn là tạo một mẫu chủ đề mới, thay vì thêm phương thức getCacheContexts () ghi đè lên thứ tự tự nhiên của các bối cảnh bộ đệm và có thể phá vỡ siêu dữ liệu sâu hơn trong mảng xây dựng của bạn.


Đây là một bản tóm tắt rất tốt của vấn đề. Nhưng tôi nghĩ rằng kết luận trong 3) là có vấn đề, bởi vì bạn không chỉ phá vỡ rằng siêu dữ liệu bộ nhớ cache của riêng bạn có thể nổi lên mà còn có thể nằm sâu hơn bên trong mảng kết xuất và bạn có thể không nhận ra.
4k4

Vì vậy, bạn sẽ đề nghị tạo một mẫu chủ đề mới? Để bảo quản sủi bọt?
oknate

Có, chỉ sử dụng mẫu khối để thêm những thứ bên ngoài. Xây dựng bên trong khối trong build (). Sử dụng các mẫu tùy chỉnh cho điều này hoặc sử dụng các yếu tố kết xuất, như bảng hoặc mẫu cốt lõi như các liên kết.
4k4

OK, tôi sẽ cập nhật câu trả lời.
oknate

Ugh, tôi đã không nhận ra rằng việc khoan vào Twig sẽ bỏ qua siêu dữ liệu có thể lưu trong bộ nhớ cache. Điều này có thể có nghĩa là cuối cùng chúng ta cần sử dụng phương thức tùy chỉnh của riêng mình để đi sâu vào (điều này làm cho phần mở rộng twig trở nên vô dụng) để chúng ta bảo toàn siêu dữ liệu trong khi đi xuống mức thấp hơn. Tìm tốt
LionsAd

4

Đối với bất cứ ai khác tìm thấy ...

Lý do mà kết xuất content(hoặc content|without()) hoạt động là có một phần tử trong mảng content['#cache']kết xuất có chứa tất cả các siêu dữ liệu có thể lưu trong bộ nhớ cache cho nội dung.

Nếu bạn không cho phép điều này được hiển thị trong twig, contenthoặc {{'#cache': content['#cache']|render }}, trang sẽ không biết nó có siêu dữ liệu có thể lưu trong bộ nhớ cache (ví dụ: nó không bao giờ nổi bong bóng).

Âm thanh như bạn không làm twig tùy chỉnh mặc dù. Nếu bạn đang sử dụng một cái gì đó như Varnish, đó cũng có thể là thủ phạm cho người dùng ẩn danh.


3

Tôi cũng gặp phải vấn đề này và cách giải quyết mà tôi nghĩ ra là tạo ra một biến block_content mới dựa trên phiên bản được lọc của biến nội dung chính trừ bất kỳ trường tùy chỉnh nào tôi muốn hiển thị thủ công:

{% set block_content = content|without('field_mycustomfield', 'field_mycustomfield2') %}

Sau đó, thay vì hiển thị biến "content.body" ngay sau đó, tôi gọi:

{{ block_content }}

Nếu bạn muốn kết xuất từng trường riêng lẻ, bạn có thể tiếp tục thêm chúng vào bộ lọc "không có" để kết xuất block_content không làm gì cả ngoại trừ sửa lỗi bộ đệm.


0

Phương pháp dễ dàng hơn để đạt được điều này là bằng cách khai báo và định nghĩa getCacheContexts()phương thức


  public function build() {

    $search_form = \Drupal::formBuilder()->getForm('Drupal\mymodule\Form\SearchForm');
    return [
      'search_form' => $search_form
    ];

  }

  /**
   * {@inheritdoc}
   */
  public function getCacheMaxAge() {
    // If you need to redefine the Max Age for that block
    return 0;
  }

  /**
   * {@inheritdoc}
   */
  public function getCacheContexts() {
    return ['url.path', 'url.query_args'];
  }

Kiểm tra tài liệu về bộ nhớ đệm , nó sẽ chứa mọi thứ bạn cần;)


Điều này không còn hoạt động nữa theo cách các khối được hiển thị ngay bây giờ, xem drupal.stackexchange.com/questions/288881/ mẹo
4k4
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.