Özel bloklarda önbellek bağlamlarını ayarlamanın doğru yolu nedir?


13

Sayfa başına benzersiz olması gereken bir bloğun oturumu kapatılmış kullanıcılar için olmadığı bir sorunla karşılaştım. Sorun özel filtreler (bir tür maruz kalan filtreler için özel bir yedek gibi. / Admin / structure / block yerleştirilen blok) içeren bir görünüm arama sayfasında sahip özel bir blok eklentisidir.

Drupal 8 hakkında öğrendiklerime dayanarak, önbellek bağlamlarını derleme dizime ekledim:

  public function build() {

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

  }

Ancak bu yanlış görünüyor gibi görünüyor, çünkü oturumu kapattığında, blok ilk görünümde önbelleğe alınacak ve url değiştiğinde, bloğun yeni bir sürümünü göstermiyordu.

Soruna neden olan görünüm sayfası olabileceğini düşündüm, ancak görünüm sayfasında önbelleğe almayı kapattığımda bile sorun devam etti.

Örneğin, bir preprocess_block kanca kullanarak sorunu çeşitli şekillerde düzeltmek başardı:

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

Ama beni rahatsız etti, sadece önbellek bağlamlarını bloğumun inşa dizisine koyamadım.

Bloğum BlockBase'i genişlettiğinden, özellikle çekirdek içindeki bazı modüllerin bu şekilde yapıldığını gördüğüm için getCacheContexts () yöntemini denemeye karar verdim.

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

Bu da sorunu düzeltti, ancak ilginç bir şekilde, önişlem bloğu işlevindeki değişkenleri çıkardığımda, bunlar $ değişkenlerde ['# cache'] ['bağlamlar'] göstermiyorlar, ancak $ değişkenleri ['öğelerinde gösteriliyorlar '] [' # cache '] [' bağlamları]

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

Bunun nasıl çalıştığını ve neden yapı işlevinden çalışmadığını anlamaya çalışıyorum.

ViewMultiple () işlevinde /core/modules/block/src/BlockViewBuilder.php dosyasına bakıldığında, önbellek etiketlerini varlıktan ve eklentiden alıyor gibi görünüyor:

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

Bu, blok eklentime neden getCacheContexts () yöntemi eklenmesinin bağlamları bloğuma eklediğini açıklıyor. Ayrıca, aynı sınıftaki preRender yöntemine bakıldığında, Drupal 8'de önbellek eklemenin bir #cache eklemesi gibi göründüğü için beni şaşırtan blok oluşturma işlevinde önbellek dizisini kullanmıyor gibi görünüyor öğeleri oluşturmak için öğe.

Benim sorum şu,

1) Önbellek bağlamları bir blok eklentisindeki doğrudan diziye eklenir mi?

2) Öyleyse, bunun bir yolu var mı, bunu yapı dizisinin alt öğesine eklememiz gerekiyor mu?

3) Doğrudan eklenen bağlam göz ardı edilirse, getCacheContexts () eklenmesi, özel modüllerde blok eklentilerine gitmenin yolu mudur?


1
1) Hayır, blok içeriğiniz aslında bir seviye düştü ve daha sonra birleştirilmelidir. 2) Gerekli değildir, çünkü 1, 3) getCacheContexts () yöntemini uygulamak daha kolay / temiz olabilir, ancak gerekli olmamalıdır. Anonim kullanıcılardan açıkça bahsediyorsunuz, normal kimliği doğrulanmış kullanıcıları da etkilemediğinden emin misiniz? Dynamic_page_cache özelliğini devre dışı bırakırsanız sorun ortadan kalkar mı? Dahili sayfa önbelleği yine de url / query argümanlarına göre değiştiğinden, yalnızca anon kullanıcılarını etkiliyorsa garip bir şey olması gerekir.
Berdir

1
Dinamik sayfa önbelleğini devre dışı bırakmak sorunu çözmez.
oknate

1
Hm, Üst düzey öğenizin #cache dışında bir şey içermemesi bir sorun olabilir. Formunuzda #cache ayarlamayı denediniz mi? Bunlara göre değişmesi gereken formdur ve önbellek etiketleri patladığından, bu sadece işe yaramalıdır. Ve formunuzu farklı bir blokta veya başka bir yerde kullanırsanız, sadece orada da çalışmalıdır.
Berdir

1
SyndicateBlock'u hızlıca hackledim ve bu build () yöntemini kullandım: gist.github.com/Berdir/33a31b1e98caf080dae78adb731dba4c . Siteme düzgün çalıştığında, önbellek bağlamları cache_render tablosunda görünür ve doğru istek URI'sı görüntülenir. Aynı şeyi deneyebilir misin? Bana sitenizde çok garip bir şeyler oluyor gibi görünüyor
Berdir

2
Standart blok şablonunu veya özel bir şablon mu kullanıyorsunuz? Bkz. Drupal.stackexchange.com/questions/217884/…
4k4

Yanıtlar:


9

Çoğu durumda, önbellek içeriğini doğrudan build () yönteminizde döndürdüğünüz oluşturma dizisine ayarlarsınız.

Sonunda sorunumun ne olduğunu @Berdir ve @ 4k4 yardımıyla buldum. Block - myblock.html.twig gibi özel bir şablon kullanıyorsanız ve değişkenleri {{content}} gibi aynı anda değil de {{content.foo}} gibi tek tek çıktılarsanız, önbellek içerikleriniz oturumu kapatıldığında doğrudan blok oluşturma dizinize geçti. Bkz . Özel bloklarda önbellek bağlamlarını ayarlamanın doğru yolu nedir?

Yani, orijinal soruyu cevaplamak için:

1) Doğrudan özel bir blok eklentisine aktarılan önbellek bağlamları bazen yok sayılır. SyndicateBlock öğesini değiştirerek ve ardından değişken bloğunu ayrı ayrı çıktıladığınız syndicate.html.php tema bloğunuzda özel bir şablon oluşturarak bunu test edebilirsiniz :

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

URL bağımsız değişkenlerini değiştirdikçe, bloğun önbellek içeriğine uymadığını görürsünüz.

Şimdi tüm içeriği bir parça olarak çıkarırsanız, çalışır:

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

Şimdi, önbellek içeriğine saygı duyuyor ve blok sayfa başına benzersiz.

2) Şimdilik, bu soruna geçici bir çözüm bulmak için, bloğunuzdakileri kendi şablonuyla çıktılayabilirsiniz.

 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']]
    ];

  }

Bu, blok modülünün ezoterik önbellek istisnalarını atlatır ve formunuz artık oturum kapatıldığında sayfa başına benzersizdir.

3) Bunu düzeltmek için kendi tema şablonunuzu oluşturmalı mı yoksa özel Block eklentinize getCacheContexts () için bir yöntem mi eklemelisiniz? Önbellek bağlamlarının doğal köpürme sırasını geçersiz kılan ve meta dizisini derleme dizinizde daha derinlere ayırabilecek bir getCacheContexts () yöntemi eklemek yerine yeni bir tema şablonu oluşturmak daha iyidir.


Bu sorunun çok iyi bir özeti. Ancak 3) 'ün sonucunun sorunlu olduğunu düşünüyorum, çünkü sadece kendi önbellek meta verilerinizin patlayabileceğini değil, aynı zamanda render dizisinin içinde daha derin olabileceğini ve farkında olmayabileceğinizi kırıyorsunuz.
4k4

Yeni bir tema şablonu oluşturmayı mı öneriyorsunuz? Açık kabarcıklanma korumak için?
oknate

Evet, blok şablonunu yalnızca dışarıya bir şeyler eklemek için kullanın. Build () içinde bloğun içini oluşturun. Bunun için özel şablonlar kullanın veya tablo gibi oluşturma öğeleri veya bağlantılar gibi çekirdek bir şablon kullanın.
4k4

Tamam, cevabı güncelleyeceğim.
oknate

Ugh, Twig'in sondajının önbelleğe alınabilir meta verileri yok sayacağını fark etmedim. Bu, delme işlemi için sonunda kendi özel yöntemimizi kullanmamız gerektiği anlamına gelebilir (bu da dal uzantısını işe yaramaz hale getirir), böylece daha düşük seviyelere inerken meta verileri koruyalım. İyi bulmak!
LionsReklam

4

Bunu bulan herkes için ...

Oluşturmanın content(veya content|without()) çalışmasının nedeni, oluşturma dizisinde content['#cache']içeriğin önbelleğe alınabilir tüm meta verilerini içeren bir öğe olmasıdır.

Bunun dalda oluşturulmasına izin vermezseniz, ya contentda {{'#cache': content['#cache']|render }}, sayfa önbelleğe alınabilir meta verilere sahip olduğunu bilmez (örneğin, asla kabarmaz).

Gerçi özel bir dal yapmıyorsunuz. Vernik gibi bir şey kullanıyorsanız, bu anonim kullanıcılar için de suçlu olabilir.


3

Ben de bu sorunu içine koştu ve ben geldi geçici çözüm el ile oluşturmak istediğiniz herhangi bir özel alanlar hariç ana içerik değişkeninin filtrelenmiş bir sürümünü temel alan yeni bir block_content değişkeni oluşturmak oldu:

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

Daha sonra "content.body" değişkenini daha sonra oluşturmak yerine şunu çağırırım:

{{ block_content }}

Her alanı ayrı ayrı işlemek istiyorsanız, onları "olmadan" filtresine eklemeye devam edebilirsiniz, böylece block_content oluşturmanın düzeltme önbelleğe alması dışında hiçbir şey yapmaması sağlanır.


0

Bunu başarmanın daha kolay yöntemi, getCacheContexts()yöntemi beyan etmek ve tanımlamaktır.


  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'];
  }

Check out CacheableDependency belgelerini olması gerektiği size gereken her şeyi içerir;)


Artık blokların oluşturulma şekli artık işe yaramıyor, bkz. Drupal.stackexchange.com/questions/288881/…
4k4
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.