"Fossies" - the Fresh Open Source Software Archive

Member "drupal-8.9.10/core/lib/Drupal/Core/Form/FormCache.php" (26 Nov 2020, 6959 Bytes) of package /linux/www/drupal-8.9.10.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) PHP source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "FormCache.php" see the Fossies "Dox" file reference documentation.

    1 <?php
    2 
    3 namespace Drupal\Core\Form;
    4 
    5 use Drupal\Component\Utility\Crypt;
    6 use Drupal\Core\Access\CsrfTokenGenerator;
    7 use Drupal\Core\Extension\ModuleHandlerInterface;
    8 use Drupal\Core\KeyValueStore\KeyValueExpirableFactoryInterface;
    9 use Drupal\Core\PageCache\RequestPolicyInterface;
   10 use Drupal\Core\Session\AccountInterface;
   11 use Drupal\Core\Site\Settings;
   12 use Psr\Log\LoggerInterface;
   13 use Symfony\Component\HttpFoundation\RequestStack;
   14 
   15 /**
   16  * Encapsulates the caching of a form and its form state.
   17  *
   18  * @ingroup form_api
   19  */
   20 class FormCache implements FormCacheInterface {
   21 
   22   /**
   23    * The factory for expirable key value stores used by form cache.
   24    *
   25    * @var \Drupal\Core\KeyValueStore\KeyValueExpirableFactoryInterface
   26    */
   27   protected $keyValueExpirableFactory;
   28 
   29   /**
   30    * The CSRF token generator to validate the form token.
   31    *
   32    * @var \Drupal\Core\Access\CsrfTokenGenerator
   33    */
   34   protected $csrfToken;
   35 
   36   /**
   37    * The current user.
   38    *
   39    * @var \Drupal\Core\Session\AccountInterface
   40    */
   41   protected $currentUser;
   42 
   43   /**
   44    * The module handler.
   45    *
   46    * @var \Drupal\Core\Extension\ModuleHandlerInterface
   47    */
   48   protected $moduleHandler;
   49 
   50   /**
   51    * Logger channel.
   52    *
   53    * @var \Drupal\Core\Logger\LoggerChannelInterface
   54    */
   55   protected $logger;
   56 
   57   /**
   58    * The config factory.
   59    *
   60    * @var \Drupal\Core\Config\ConfigFactoryInterface
   61    */
   62   protected $configFactory;
   63 
   64   /**
   65    * The request stack.
   66    *
   67    * @var \Symfony\Component\HttpFoundation\RequestStack
   68    */
   69   protected $requestStack;
   70 
   71   /**
   72    * A policy rule determining the cacheability of a request.
   73    *
   74    * @var \Drupal\Core\PageCache\RequestPolicyInterface
   75    */
   76   protected $requestPolicy;
   77 
   78   /**
   79    * The app root.
   80    *
   81    * @var string
   82    */
   83   protected $root;
   84 
   85   /**
   86    * Constructs a new FormCache.
   87    *
   88    * @param string $root
   89    *   The app root.
   90    * @param \Drupal\Core\KeyValueStore\KeyValueExpirableFactoryInterface $key_value_expirable_factory
   91    *   The key value expirable factory, used to create key value expirable
   92    *   stores for the form cache and form state cache.
   93    * @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
   94    *   The module handler.
   95    * @param \Drupal\Core\Session\AccountInterface $current_user
   96    *   The current user.
   97    * @param \Drupal\Core\Access\CsrfTokenGenerator $csrf_token
   98    *   The CSRF token generator.
   99    * @param \Psr\Log\LoggerInterface $logger
  100    *   A logger instance.
  101    * @param \Symfony\Component\HttpFoundation\RequestStack $request_stack
  102    *   The request stack.
  103    * @param \Drupal\Core\PageCache\RequestPolicyInterface $request_policy
  104    *   A policy rule determining the cacheability of a request.
  105    */
  106   public function __construct($root, KeyValueExpirableFactoryInterface $key_value_expirable_factory, ModuleHandlerInterface $module_handler, AccountInterface $current_user, CsrfTokenGenerator $csrf_token, LoggerInterface $logger, RequestStack $request_stack, RequestPolicyInterface $request_policy) {
  107     $this->root = $root;
  108     $this->keyValueExpirableFactory = $key_value_expirable_factory;
  109     $this->moduleHandler = $module_handler;
  110     $this->currentUser = $current_user;
  111     $this->logger = $logger;
  112     $this->csrfToken = $csrf_token;
  113     $this->requestStack = $request_stack;
  114     $this->requestPolicy = $request_policy;
  115   }
  116 
  117   /**
  118    * {@inheritdoc}
  119    */
  120   public function getCache($form_build_id, FormStateInterface $form_state) {
  121     if ($form = $this->keyValueExpirableFactory->get('form')->get($form_build_id)) {
  122       if ((isset($form['#cache_token']) && $this->csrfToken->validate($form['#cache_token'])) || (!isset($form['#cache_token']) && $this->currentUser->isAnonymous())) {
  123         $this->loadCachedFormState($form_build_id, $form_state);
  124 
  125         // Generate a new #build_id if the cached form was rendered on a
  126         // cacheable page.
  127         $build_info = $form_state->getBuildInfo();
  128         if (!empty($build_info['immutable'])) {
  129           $form['#build_id_old'] = $form['#build_id'];
  130           $form['#build_id'] = 'form-' . Crypt::randomBytesBase64();
  131           $form['form_build_id']['#value'] = $form['#build_id'];
  132           $form['form_build_id']['#id'] = $form['#build_id'];
  133           unset($build_info['immutable']);
  134           $form_state->setBuildInfo($build_info);
  135         }
  136         return $form;
  137       }
  138     }
  139   }
  140 
  141   /**
  142    * Loads the cached form state.
  143    *
  144    * @param string $form_build_id
  145    *   The unique form build ID.
  146    * @param \Drupal\Core\Form\FormStateInterface $form_state
  147    *   The current state of the form.
  148    */
  149   protected function loadCachedFormState($form_build_id, FormStateInterface $form_state) {
  150     if ($stored_form_state = $this->keyValueExpirableFactory->get('form_state')->get($form_build_id)) {
  151       // Re-populate $form_state for subsequent rebuilds.
  152       $form_state->setFormState($stored_form_state);
  153 
  154       // If the original form is contained in include files, load the files.
  155       // @see \Drupal\Core\Form\FormStateInterface::loadInclude()
  156       $build_info = $form_state->getBuildInfo();
  157       $build_info += ['files' => []];
  158       foreach ($build_info['files'] as $file) {
  159         if (is_array($file)) {
  160           $file += ['type' => 'inc', 'name' => $file['module']];
  161           $this->moduleHandler->loadInclude($file['module'], $file['type'], $file['name']);
  162         }
  163         elseif (file_exists($file)) {
  164           require_once $this->root . '/' . $file;
  165         }
  166       }
  167     }
  168   }
  169 
  170   /**
  171    * {@inheritdoc}
  172    */
  173   public function setCache($form_build_id, $form, FormStateInterface $form_state) {
  174     // Cache forms for 6 hours by default.
  175     $expire = Settings::get('form_cache_expiration', 21600);
  176 
  177     // Ensure that the form build_id embedded in the form structure is the same
  178     // as the one passed in as a parameter. This is an additional safety measure
  179     // to prevent legacy code operating directly with
  180     // \Drupal::formBuilder()->getCache() and \Drupal::formBuilder()->setCache()
  181     // from accidentally overwriting immutable form state.
  182     if (isset($form['#build_id']) && $form['#build_id'] != $form_build_id) {
  183       $this->logger->error('Form build-id mismatch detected while attempting to store a form in the cache.');
  184       return;
  185     }
  186 
  187     // Cache form structure.
  188     if (isset($form)) {
  189       if ($this->currentUser->isAuthenticated()) {
  190         $form['#cache_token'] = $this->csrfToken->get();
  191       }
  192       unset($form['#build_id_old']);
  193       $this->keyValueExpirableFactory->get('form')->setWithExpire($form_build_id, $form, $expire);
  194     }
  195 
  196     if ($data = $form_state->getCacheableArray()) {
  197       $this->keyValueExpirableFactory->get('form_state')->setWithExpire($form_build_id, $data, $expire);
  198     }
  199   }
  200 
  201   /**
  202    * {@inheritdoc}
  203    */
  204   public function deleteCache($form_build_id) {
  205     $this->keyValueExpirableFactory->get('form')->delete($form_build_id);
  206     $this->keyValueExpirableFactory->get('form_state')->delete($form_build_id);
  207   }
  208 
  209 }