বর্তমান নোডের উপর নির্ভর করে আমার কাস্টম ব্লকের সামগ্রীগুলি কীভাবে সঠিকভাবে সেটআপ করব?


19

আমার কাছে এটির খুব বেসিক ব্লক রয়েছে যা কেবলমাত্র নোডের আইডি দেখায়।

<?php

/**
 * @file
 * Contains \Drupal\mymodule\Plugin\Block\ExampleEmptyBlock.
 */

namespace Drupal\mymodule\Plugin\Block;

use Drupal\Core\Block\BlockBase;
use Drupal\Core\Cache\Cache;

/**
 * @Block(
 *   id = "example_empty",
 *   admin_label = @Translation("Example: empty block")
 * )
 */
class ExampleEmptyBlock extends BlockBase {

  /**
   * {@inheritdoc}
   */
  public function build() {
    $node = \Drupal::routeMatch()->getParameter('node');
    $build = array();

    if ($node) {
      $config = \Drupal::config('system.site');

      $build = array(
        '#type' => 'markup',
        '#markup' => '<p>' . $node->id() . '<p>',
        '#cache' => array(
          'tags' => $this->getCacheTags(),
          'contexts' => $this->getCacheContexts(),
        ),
      );
    }

    return $build;
  }

  /**
   * {@inheritdoc}
   */
  public function getCacheTags() {
    $node = \Drupal::routeMatch()->getParameter('node');
    return Cache::mergeTags(parent::getCacheTags(), ["node:{$node->id()}"]);
  }

  /**
   * {@inheritdoc}
   */
  public function getCacheContexts() {
    return Cache::mergeContexts(parent::getCacheContexts(), ['user.node_grants:view']);
  }

}

তবে একবার ক্যাশে হয়ে গেলে, ব্লকটি একই থাকে, আমি কোন নোডে যাই না কেন। আমি কীভাবে প্রতি নোড আইডিতে ফলাফলটি সঠিকভাবে ক্যাশে করব?


1
দেখুন এ getCacheTags()BlockBase থেকে, আপনি শুধু প্রয়োজন একটি ট্যাগ আপনার নোড প্রতিনিধিত্ব যোগ করুন (নোড: {NID})। দুঃখিত আমি এখনই তাড়াহুড়ো করছি, আমি আরও পরে আরও ভাল করে ব্যাখ্যা করতে পারি,
ভ্যাগনার

উত্তর:


31

এটি মন্তব্য সহ সম্পূর্ণ কার্যকারী কোড।

namespace Drupal\module_name\Plugin\Block;

use Drupal\Core\Block\BlockBase;
use Drupal\Core\Cache\Cache;

/**
 * Provides a Node cached block that display node's ID.
 *
 * @Block(
 *   id = "node_cached_block",
 *   admin_label = @Translation("Node Cached")
 * )
 */
class NodeCachedBlock extends BlockBase {
  public function build() {
    $build = array();
    //if node is found from routeMatch create a markup with node ID's.
    if ($node = \Drupal::routeMatch()->getParameter('node')) {
      $build['node_id'] = array(
        '#markup' => '<p>' . $node->id() . '<p>',
      );
    }
    return $build;
  }

  public function getCacheTags() {
    //With this when your node change your block will rebuild
    if ($node = \Drupal::routeMatch()->getParameter('node')) {
      //if there is node add its cachetag
      return Cache::mergeTags(parent::getCacheTags(), array('node:' . $node->id()));
    } else {
      //Return default tags instead.
      return parent::getCacheTags();
    }
  }

  public function getCacheContexts() {
    //if you depends on \Drupal::routeMatch()
    //you must set context of this block with 'route' context tag.
    //Every new route this block will rebuild
    return Cache::mergeContexts(parent::getCacheContexts(), array('route'));
  }
}

আমি এটি পরীক্ষা করেছি; এটা কাজ করে।

আপনার মডিউল ফোল্ডারে নোডকচেডব্লক.এফপি নামের একটি ফাইলের মধ্যে কেবল কোডটি রেখে দিন, এর নাম স্থান। মডিউল_নাম} পরিবর্তন করুন, ক্যাশে সাফ করুন এবং এটি ব্যবহার করুন।


সুতরাং কৌতুকটি হ'ল #cacheবিল্ড ফাংশনে সেটিংস মুছে ফেলা এবং কেবল সর্বজনীন ফাংশন যুক্ত করা?
অ্যালেক্স

3
আপনি ক্যাশে ট্যাগ এবং প্রসঙ্গটি কোথায় সেট করেছেন তা বিবেচ্য নয়।
4k4

ঠিক আছে, আমি মনে করি এটি আরও বোধগম্য, কারণ আমরা একটি ব্লক তৈরি করছি, তাই ব্লককে ক্যাশে করা দরকার। আপনি যদি ভবিষ্যতে আপনার ব্লক পরিবর্তন করেন (যেমন কিছু অতিরিক্ত রেন্ডার উপাদান রেখে) আপনার ব্লকটি কাজ করবে।
ভ্যাগনার

@ 4k4 url.path দেখে মনে হয়েছে এটি খুব কার্যকর হয়েছে। পার্থক্য কি?
অ্যালেক্স

2
@ ভ্যাগনার: রেন্ডার অ্যারেতে ক্যাশে ট্যাগ / প্রসঙ্গ স্থাপন করাও একটি খারাপ ধারণা নয়, কারণ আপনার ডেটা যেখানে রয়েছে সেখানে এটি নির্ভর করে। এবং এটি সর্বদা বুদবুদ হবে, সুতরাং আপনাকে উপরের উপাদানগুলির বিষয়ে চিন্তা করতে হবে না। BTW। আপনার কোড দুর্দান্ত, ক্যাশিংয়ের সমস্যাগুলি খুব ভালভাবে ব্যাখ্যা করে।
কে 4

13

এটি করার সবচেয়ে সহজ উপায় হ'ল প্লাগইন / ব্লক প্রসঙ্গ সিস্টেমের উপর নির্ভর করা।

আমার উত্তর দেখুন কীভাবে আমি এমন একটি ব্লক তৈরি করব যা বর্তমান নোড সামগ্রীটি টানবে?

আপনাকে কেবল আপনার ব্লক টীকায় এইভাবে একটি নোড প্রসঙ্গ সংজ্ঞা রাখতে হবে:

*   context = {
*     "node" = @ContextDefinition("entity:node", label = @Translation("Node"))
*   }

এবং তারপরে এটি ব্যবহার করুন: $this->getContextValue('node')

এই সম্পর্কে দুর্দান্ত জিনিস হ'ল দ্রুপাল তারপরে আপনার জন্য ক্যাশিংয়ের যত্ন নেবে। স্বয়ংক্রিয়ভাবে. কারণ এটি জানে যে ডিফল্ট (এবং মূল হিসাবে কেবল যায়) নোড প্রসঙ্গটি বর্তমান নোড। এবং এটি কোথায় থেকে আসছে তা জানে তাই ক্যাশে প্রসঙ্গ এবং ক্যাশে ট্যাগগুলি স্বয়ংক্রিয়ভাবে যুক্ত হয় are

এর মাধ্যমে \Drupal\Core\Plugin\ContextAwarePluginBase::getCacheContexts()এবং সংশ্লিষ্ট getCacheTags()পদ্ধতি, BlockBase / আপনার ব্লক বর্গ এবং উত্তরাধিকারী সেই পদ্ধতি থেকে প্রসারিত করে।


আপনি এর সাথে প্রতিস্থাপন \Drupal::routeMatch()->getParameter('node')করেন $this->getContextValue('node')এবং আপনি কোডের এক লাইনের সাথে পুরো ক্যাশিংয়ের সমস্যাটি সমাধান করেন? গ্রেট!
কে 4

1
এখন পর্যন্ত ধন্যবাদ! আপনি একটি সম্পূর্ণ কোড উদাহরণ প্রদান করতে পারেন?
অ্যালেক্স

@ অ্যালেক্স: আমি আপনার প্রশ্ন সম্পাদনা করেছি। আপনি যদি কোনও ত্রুটি খুঁজে পান তবে দয়া করে চেক করুন এবং কোডটি পরিবর্তন করুন।
4k4

@ 4 কে 4 আমি এটি চেষ্টা করে দেখিনি কারণ অন্যান্য সমাধানটিও কার্যকর কাজ করে
অ্যালেক্স

@ অ্যালেক্স - সম্পূর্ণ কোড উদাহরণ: drupal.stackexchange.com/a/205155/15055
লেইম্যানেক্স

7

আপনি যদি আপনার ব্লক প্লাগইনটির শ্রেণি থেকে উদ্ভূত হন তবে Drupal\Core\Block\BlockBaseক্যাশে ট্যাগ এবং প্রসঙ্গ সেট করার জন্য আপনার কাছে দুটি পদ্ধতি থাকবে।

  • getCacheTags()
  • getCacheContexts()

উদাহরণস্বরূপ, বুক মডিউল ব্লক নিম্নলিখিত পদ্ধতিগুলি প্রয়োগ করে।

  /**
   * {@inheritdoc}
   */
  public function getCacheContexts() {
    return Cache::mergeContexts(parent::getCacheContexts(), ['route.book_navigation']);
  }

ফোরাম মডিউল ব্লক নিম্নলিখিত কোড ব্যবহার করে।

  /**
   * {@inheritdoc}
   */
  public function getCacheContexts() {
    return Cache::mergeContexts(parent::getCacheContexts(), ['user.node_grants:view']);
  }

  /**
   * {@inheritdoc}
   */
  public function getCacheTags() {
    return Cache::mergeTags(parent::getCacheTags(), ['node_list']);
  }

আপনার ক্ষেত্রে, আমি নিম্নলিখিত কোডটি ব্যবহার করব।

  /**
   * {@inheritdoc}
   */
  public function getCacheTags() {
    $node = \Drupal::routeMatch()->getParameter('node');
    return Cache::mergeTags(parent::getCacheTags(), ["node:{$node->id()}"]);
  }

আপনি ব্লকটি একেবারে অপ্রয়োজনীয় করে তুলতে নিম্নলিখিত পদ্ধতিটিও ব্যবহার করতে পারেন (এমনকি আমি এড়াতে চাইলেও)। এটি অন্যান্য ক্ষেত্রেও কার্যকর হতে পারে।

  /**
   * {@inheritdoc}
   */
  public function getCacheMaxAge() {
    return 0;
  }

যোগ করার জন্য মনে রাখুন use Drupal\Core\Cache\Cache;, ফাইল উপরে আপনি ব্যবহার করতে যাচ্ছি যদি Cacheবর্গ।


ধন্যবাদ, তবে / নোড / 2 তে আমার ক্যাশে সাফ করার পরে প্রথম স্থানে নোড / 1 পরিদর্শন করার পরে ব্লকটি 1 আউটপুট দেয়
অ্যালেক্স

2
আপনি যদি সক্ষম মডিউলটি সম্পাদনা করে থাকেন তবে এডিট করার আগে আপনাকে প্রথমে এটি আনইনস্টল করতে হবে। ক্যাশে সাফ করা যথেষ্ট নয়।
kiamlaluno

ঠিক আছে, তবে আশ্চর্যজনকভাবে ম্যাক্সএজ 0 টি কাজ করে!
অ্যালেক্স

এছাড়াও, আপনার ব্লক শ্রেণিটি কি BlockBaseক্লাসটিকে পিতামাতার শ্রেণি হিসাবে ব্যবহার করে ?
kiamlaluno

হ্যাঁ এটি এটি ব্যবহার করে
অ্যালেক্স

3

আপনি যখন একটি রেন্ডার অ্যারে তৈরি করেন, সর্বদা সঠিক মেটাডেটা সংযুক্ত করুন:

use Drupal\Core\Cache\Cache;

$build['node_id'] = [
  '#markup' => '<p>' . $node->id() . '<p>',
  '#cache' => [
    'tags' => $node->getCacheTags(),
    // add a context if the node is dependent on the route match
    'contexts' => ['route'],
  ],
];

এটি ব্লক নির্দিষ্ট নয় এবং ব্লক প্লাগইনগুলি ক্যাশে নির্ভরতা পদ্ধতিগুলি getCacheTags (), getCacheContext () এবং getCacheMaxAge () প্রতিস্থাপন নয়। এগুলি কেবলমাত্র অতিরিক্ত ক্যাশে মেটাডেটা জন্য ব্যবহার করা উচিত, যা রেন্ডার অ্যারের মাধ্যমে সরবরাহ করা যায় না।

ডকুমেন্টেশন দেখুন:

"এটি সর্বাধিক গুরুত্বের বিষয় যে আপনি রেন্ডার অ্যারে এর ক্যাচিবিলিটি রেন্ডার এপিআইকে জানান।"

https://www.drupal.org/docs/8/api/render-api/cacheability-of-render-arrays

এই উদাহরণটি দেখুন কীভাবে দ্রুপাল অটো-প্লেসোল্ডারিং এবং অলস-বিল্ডিংয়ের মাধ্যমে ক্যাশেটি অনুকূলকরণের সময় প্রয়োজনীয় ক্যাশে মেটাডেটা সরবরাহ করার জন্য একটি রেন্ডার অ্যারে সরবরাহের প্রত্যাশা করে ব্যবহারকারী প্রসঙ্গের সাথে কাস্টম ব্লকে ব্যবহারকারী নির্দিষ্ট ক্যাশে ট্যাগগুলি সেট করতে সমস্যা


আমি মনে করি না এটি ব্লক অবজেক্টের ক্যাশে সেট করতে পারে। '#মার্কআপ' কেবল একটি রেন্ডার এলিমেন্ট অবজেক্ট এবং ক্যাশে প্রসঙ্গ বা ট্যাগ সেট করার কোনও কারণ নেই। ক্যাশে অকার্যকর হলে পুনর্নির্মাণের জন্য ব্লক অবজেক্ট needs
ভ্যাগনার

#markupঅন্যান্য রেন্ডার উপাদান হিসাবে একই ক্যাশে করা যেতে পারে। এই ক্ষেত্রে এটি মার্কআপ নয়, তবে ব্লকটি, যা ক্যাশেড এবং এখানে সমস্যা রয়েছে। আপনি এটি ক্যাশে ট্যাগগুলির সাথে সমাধান করতে পারবেন না, কারণ সেগুলি কেবলমাত্র অকার্যকর হয়ে যায়, যদি ডাটাবেসে নোড পরিবর্তন করা হয়।
4k4

@ ভ্যাগনার আপনি একটি ব্লক অবজেক্টের ক্যাশে সেট করতে পারেন; BlockBaseশ্রেণী এমনকি প্রয়োজনীয় মেথড।
kiamlaluno

1
আমার return [ '#markup' => render($output), '#cache' => [ 'contexts' => ['url'] ] ];জন্য প্রতিটি ইউআরএল ক্যাচিংয়ের জন্য দুর্দান্ত কাজ করে।
লেইম্যানেক্স

1
হ্যাঁ, @leymannx, এটি এতটা সহজ। এই থ্রেডগুলি সমস্যাটিকে ওভারথিংক করছে বলে মনে হচ্ছে।
কে 4

0

এখানে সমস্যা হ'ল বিল্ড ফাংশনে সঠিক স্থানে ক্যাশে প্রসঙ্গগুলি ঘোষণা করা হয় না:

class ExampleEmptyBlock extends BlockBase {

  /**
   * {@inheritdoc}
   */
  public function build() {
   $node = \Drupal::routeMatch()->getParameter('node');
   $build = array();

   if ($node) {
    $config = \Drupal::config('system.site');

    $build = array(
    '#type' => 'markup',
    '#markup' => '<p>' . $node->id() . '<p>',
    '#cache' => array(
      'tags' => $this->getCacheTags(),
      'contexts' => $this->getCacheContexts(),
    ),
   );
 }
 return $build;
 }
}

যদি আপনি সেই ব্লকটিকে নন নোডে কল করেন তবে বিল্ড ফাংশনটি খালি অ্যারেটি ফেরত দেয়, সুতরাং এই ব্লকের জন্য কোনও ক্যাশে প্রসঙ্গ নেই এবং সেই আচরণটি ড্রুপাল দ্বারা ক্যাশে করা হবে: এই ব্লকের প্রদর্শনটি সঠিকভাবে অকার্যকর হবে না বা রেন্ডার হবে না।

সমাধানটি কেবলমাত্র আরম্ভ করার জন্য every প্রতিবার ক্যাশে প্রসঙ্গের সাথে বিল্ড করা:

class ExampleEmptyBlock extends BlockBase {

  /**
   * {@inheritdoc}
   */
  public function build() {
   $node = \Drupal::routeMatch()->getParameter('node');

    $build = array(
    '#cache' => array(
      'tags' => $this->getCacheTags(),
      'contexts' => $this->getCacheContexts(),
    ),
   );

   if ($node) {
    $config = \Drupal::config('system.site');

    $build['#markup'] = '<p>' . $node->id() . '<p>';
    $build['#type'] = 'markup';
    }
 return $build;
 }
}

0

আমি বুঝতে পারি যে আমি এই কথোপকথনে দেরি করেছি, তবে নীচের কোডটি আমার পক্ষে কাজ করেছে:

class ExampleBlock extends BlockBase
{

  public function build()
  {
    $lcContent = '';

    $loNode = \Drupal::routeMatch()->getParameter('node');

    if (!$loNode)
    {
      return (array(
        '#type' => 'markup',
        '#cache' => array('max-age' => 0),
        '#markup' => $lcContent,
      ));
    }

    $lcContent .= "<div id='example_block' style='overflow: hidden; clear: both;'>\n";
    $lcContent .= $loNode->id();
    $lcContent .= "</div>\n";

    return (array(
      '#type' => 'markup',
      '#cache' => array('max-age' => 0),
      '#markup' => $lcContent,
    ));
  }
}

আগের চেয়ে ভাল দেরী :)
অ্যালেক্স

0

আপনি কি হুক_ব্লক_ভিউ_বিএএস_ব্লোক_আইডি_এল্টার বাস্তবায়নের চেষ্টা করেছেন?

ফাংশন হুক_ব্লক_ভিউ_বিএএস ব্লক_আইডি_এল্টার (অ্যারে & $ বিল্ড, \ দ্রুপাল ore কোর \ ব্লক \ ব্লকপ্লাগিনআইন্টারফেস $ ব্লক) $ $ বিল্ড ['# ক্যাশে'] ['সর্বাধিক বয়স'] = 0; }

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.