[ Index ]

PHP Cross Reference of Joomla 4.2.2 documentation

title

Body

[close]

/plugins/workflow/featuring/ -> featuring.php (source)

   1  <?php
   2  
   3  /**
   4   * @package     Joomla.Plugin
   5   * @subpackage  Workflow.Featuring
   6   *
   7   * @copyright   (C) 2020 Open Source Matters, Inc. <https://www.joomla.org>
   8   * @license     GNU General Public License version 2 or later; see LICENSE.txt
   9  
  10   * @phpcs:disable PSR1.Classes.ClassDeclaration.MissingNamespace
  11   */
  12  
  13  use Joomla\CMS\Application\CMSApplicationInterface;
  14  use Joomla\CMS\Event\AbstractEvent;
  15  use Joomla\CMS\Event\Table\BeforeStoreEvent;
  16  use Joomla\CMS\Event\View\DisplayEvent;
  17  use Joomla\CMS\Event\Workflow\WorkflowFunctionalityUsedEvent;
  18  use Joomla\CMS\Event\Workflow\WorkflowTransitionEvent;
  19  use Joomla\CMS\Factory;
  20  use Joomla\CMS\Form\Form;
  21  use Joomla\CMS\Language\Text;
  22  use Joomla\CMS\MVC\Model\DatabaseModelInterface;
  23  use Joomla\CMS\Plugin\CMSPlugin;
  24  use Joomla\CMS\Table\ContentHistory;
  25  use Joomla\CMS\Table\TableInterface;
  26  use Joomla\CMS\Workflow\WorkflowPluginTrait;
  27  use Joomla\CMS\Workflow\WorkflowServiceInterface;
  28  use Joomla\Component\Content\Administrator\Event\Model\FeatureEvent;
  29  use Joomla\Event\EventInterface;
  30  use Joomla\Event\SubscriberInterface;
  31  use Joomla\Registry\Registry;
  32  use Joomla\String\Inflector;
  33  
  34  // phpcs:disable PSR1.Files.SideEffects
  35  \defined('_JEXEC') or die;
  36  // phpcs:enable PSR1.Files.SideEffects
  37  
  38  /**
  39   * Workflow Featuring Plugin
  40   *
  41   * @since  4.0.0
  42   */
  43  class PlgWorkflowFeaturing extends CMSPlugin implements SubscriberInterface
  44  {
  45      use WorkflowPluginTrait;
  46  
  47      /**
  48       * Load the language file on instantiation.
  49       *
  50       * @var    boolean
  51       * @since  4.0.0
  52       */
  53      protected $autoloadLanguage = true;
  54  
  55      /**
  56       * Loads the CMS Application for direct access
  57       *
  58       * @var   CMSApplicationInterface
  59       * @since 4.0.0
  60       */
  61      protected $app;
  62  
  63      /**
  64       * The name of the supported functionality to check against
  65       *
  66       * @var   string
  67       * @since 4.0.0
  68       */
  69      protected $supportFunctionality = 'core.featured';
  70  
  71      /**
  72       * Returns an array of events this subscriber will listen to.
  73       *
  74       * @return  array
  75       *
  76       * @since   4.0.0
  77       */
  78      public static function getSubscribedEvents(): array
  79      {
  80          return [
  81              'onAfterDisplay'                  => 'onAfterDisplay',
  82              'onContentBeforeChangeFeatured'   => 'onContentBeforeChangeFeatured',
  83              'onContentBeforeSave'             => 'onContentBeforeSave',
  84              'onContentPrepareForm'            => 'onContentPrepareForm',
  85              'onContentVersioningPrepareTable' => 'onContentVersioningPrepareTable',
  86              'onTableBeforeStore'              => 'onTableBeforeStore',
  87              'onWorkflowAfterTransition'       => 'onWorkflowAfterTransition',
  88              'onWorkflowBeforeTransition'      => 'onWorkflowBeforeTransition',
  89              'onWorkflowFunctionalityUsed'     => 'onWorkflowFunctionalityUsed',
  90          ];
  91      }
  92  
  93      /**
  94       * The form event.
  95       *
  96       * @param   EventInterface  $event  The event
  97       *
  98       * @since   4.0.0
  99       */
 100      public function onContentPrepareForm(EventInterface $event)
 101      {
 102          $form = $event->getArgument('0');
 103          $data = $event->getArgument('1');
 104  
 105          $context = $form->getName();
 106  
 107          // Extend the transition form
 108          if ($context === 'com_workflow.transition') {
 109              $this->enhanceWorkflowTransitionForm($form, $data);
 110  
 111              return;
 112          }
 113  
 114          $this->enhanceItemForm($form, $data);
 115      }
 116  
 117      /**
 118       * Disable certain fields in the item form view, when we want to take over this function in the transition
 119       * Check also for the workflow implementation and if the field exists
 120       *
 121       * @param   Form      $form  The form
 122       * @param   stdClass  $data  The data
 123       *
 124       * @return  boolean
 125       *
 126       * @since   4.0.0
 127       */
 128      protected function enhanceItemForm(Form $form, $data)
 129      {
 130          $context = $form->getName();
 131  
 132          if (!$this->isSupported($context)) {
 133              return true;
 134          }
 135  
 136          $parts = explode('.', $context);
 137  
 138          $component = $this->app->bootComponent($parts[0]);
 139  
 140          $modelName = $component->getModelName($context);
 141  
 142          $table = $component->getMVCFactory()->createModel($modelName, $this->app->getName(), ['ignore_request' => true])
 143              ->getTable();
 144  
 145          $fieldname = $table->getColumnAlias('featured');
 146  
 147          $options = $form->getField($fieldname)->options;
 148  
 149          $value = $data->$fieldname ?? $form->getValue($fieldname, null, 0);
 150  
 151          $text = '-';
 152  
 153          $textclass = 'body';
 154  
 155          switch ($value) {
 156              case 1:
 157                  $textclass = 'success';
 158                  break;
 159  
 160              case 0:
 161              case -2:
 162                  $textclass = 'danger';
 163          }
 164  
 165          if (!empty($options)) {
 166              foreach ($options as $option) {
 167                  if ($option->value == $value) {
 168                      $text = $option->text;
 169  
 170                      break;
 171                  }
 172              }
 173          }
 174  
 175          $form->setFieldAttribute($fieldname, 'type', 'spacer');
 176  
 177          $label = '<span class="text-' . $textclass . '">' . htmlentities($text, ENT_COMPAT, 'UTF-8') . '</span>';
 178          $form->setFieldAttribute(
 179              $fieldname,
 180              'label',
 181              Text::sprintf('PLG_WORKFLOW_FEATURING_FEATURED', $label)
 182          );
 183  
 184          return true;
 185      }
 186  
 187      /**
 188       * Manipulate the generic list view
 189       *
 190       * @param   DisplayEvent  $event
 191       *
 192       * @since   4.0.0
 193       */
 194      public function onAfterDisplay(DisplayEvent $event)
 195      {
 196          $app = Factory::getApplication();
 197  
 198          if (!$app->isClient('administrator')) {
 199              return;
 200          }
 201  
 202          $component = $event->getArgument('extensionName');
 203          $section   = $event->getArgument('section');
 204  
 205          // We need the single model context for checking for workflow
 206          $singularsection = Inflector::singularize($section);
 207  
 208          if (!$this->isSupported($component . '.' . $singularsection)) {
 209              return true;
 210          }
 211  
 212          // List of related batch functions we need to hide
 213          $states = [
 214              'featured',
 215              'unfeatured',
 216          ];
 217  
 218          $js = "
 219              document.addEventListener('DOMContentLoaded', function()
 220              {
 221                  var dropdown = document.getElementById('toolbar-status-group');
 222  
 223                  if (!dropdown)
 224                  {
 225                      return;
 226                  }
 227  
 228                  " . json_encode($states) . ".forEach((action) => {
 229                      var button = document.getElementById('status-group-children-' + action);
 230  
 231                      if (button)
 232                      {
 233                          button.classList.add('d-none');
 234                      }
 235                  });
 236  
 237              });
 238          ";
 239  
 240          $app->getDocument()->addScriptDeclaration($js);
 241  
 242          return true;
 243      }
 244  
 245      /**
 246       * Check if we can execute the transition
 247       *
 248       * @param   WorkflowTransitionEvent  $event
 249       *
 250       * @return   boolean
 251       *
 252       * @since   4.0.0
 253       */
 254      public function onWorkflowBeforeTransition(WorkflowTransitionEvent $event)
 255      {
 256          $context    = $event->getArgument('extension');
 257          $transition = $event->getArgument('transition');
 258          $pks        = $event->getArgument('pks');
 259  
 260          if (!$this->isSupported($context) || !is_numeric($transition->options->get('featuring'))) {
 261              return true;
 262          }
 263  
 264          $value = $transition->options->get('featuring');
 265  
 266          if (!is_numeric($value)) {
 267              return true;
 268          }
 269  
 270          /**
 271           * Here it becomes tricky. We would like to use the component models featured method, so we will
 272           * Execute the normal "onContentBeforeChangeFeatured" plugins. But they could cancel the execution,
 273           * So we have to precheck and cancel the whole transition stuff if not allowed.
 274           */
 275          $this->app->set('plgWorkflowFeaturing.' . $context, $pks);
 276  
 277          // Trigger the change state event.
 278          $eventResult = $this->app->getDispatcher()->dispatch(
 279              'onContentBeforeChangeFeatured',
 280              AbstractEvent::create(
 281                  'onContentBeforeChangeFeatured',
 282                  [
 283                      'eventClass' => 'Joomla\Component\Content\Administrator\Event\Model\FeatureEvent',
 284                      'subject'    => $this,
 285                      'extension'  => $context,
 286                      'pks'        => $pks,
 287                      'value'      => $value,
 288                      'abort'      => false,
 289                      'abortReason' => '',
 290                  ]
 291              )
 292          );
 293  
 294          // Release allowed pks, the job is done
 295          $this->app->set('plgWorkflowFeaturing.' . $context, []);
 296  
 297          if ($eventResult->getArgument('abort')) {
 298              $event->setStopTransition();
 299  
 300              return false;
 301          }
 302  
 303          return true;
 304      }
 305  
 306      /**
 307       * Change Feature State of an item. Used to disable feature state change
 308       *
 309       * @param   WorkflowTransitionEvent  $event
 310       *
 311       * @return   void
 312       *
 313       * @since   4.0.0
 314       */
 315      public function onWorkflowAfterTransition(WorkflowTransitionEvent $event): void
 316      {
 317          $context       = $event->getArgument('extension');
 318          $extensionName = $event->getArgument('extensionName');
 319          $transition    = $event->getArgument('transition');
 320          $pks           = $event->getArgument('pks');
 321  
 322          if (!$this->isSupported($context)) {
 323              return;
 324          }
 325  
 326          $component = $this->app->bootComponent($extensionName);
 327  
 328          $value = $transition->options->get('featuring');
 329  
 330          if (!is_numeric($value)) {
 331              return;
 332          }
 333  
 334          $options = [
 335              'ignore_request'               => true,
 336              // We already have triggered onContentBeforeChangeFeatured, so use our own
 337              'event_before_change_featured' => 'onWorkflowBeforeChangeFeatured',
 338          ];
 339  
 340          $modelName = $component->getModelName($context);
 341  
 342          $model = $component->getMVCFactory()->createModel($modelName, $this->app->getName(), $options);
 343  
 344          $model->featured($pks, $value);
 345      }
 346  
 347      /**
 348       * Change Feature State of an item. Used to disable Feature state change
 349       *
 350       * @param   FeatureEvent  $event
 351       *
 352       * @return   boolean
 353       *
 354       * @throws   Exception
 355       * @since   4.0.0
 356       */
 357      public function onContentBeforeChangeFeatured(FeatureEvent $event)
 358      {
 359          $extension = $event->getArgument('extension');
 360          $pks       = $event->getArgument('pks');
 361  
 362          if (!$this->isSupported($extension)) {
 363              return true;
 364          }
 365  
 366          // We have allowed the pks, so we're the one who triggered
 367          // With onWorkflowBeforeTransition => free pass
 368          if ($this->app->get('plgWorkflowFeaturing.' . $extension) === $pks) {
 369              return true;
 370          }
 371  
 372          $event->setAbort('PLG_WORKFLOW_FEATURING_CHANGE_STATE_NOT_ALLOWED');
 373      }
 374  
 375      /**
 376       * The save event.
 377       *
 378       * @param   EventInterface  $event
 379       *
 380       * @return  boolean
 381       *
 382       * @since   4.0.0
 383       */
 384      public function onContentBeforeSave(EventInterface $event)
 385      {
 386          $context = $event->getArgument('0');
 387  
 388          /** @var TableInterface $table */
 389          $table = $event->getArgument('1');
 390          $isNew = $event->getArgument('2');
 391          $data  = $event->getArgument('3');
 392  
 393          if (!$this->isSupported($context)) {
 394              return true;
 395          }
 396  
 397          $keyName = $table->getColumnAlias('featured');
 398  
 399          // Check for the old value
 400          $article = clone $table;
 401  
 402          $article->load($table->id);
 403  
 404          /**
 405           * We don't allow the change of the feature state when we use the workflow
 406           * As we're setting the field to disabled, no value should be there at all
 407           */
 408          if (isset($data[$keyName])) {
 409              $this->app->enqueueMessage(Text::_('PLG_WORKFLOW_FEATURING_CHANGE_STATE_NOT_ALLOWED'), 'error');
 410  
 411              return false;
 412          }
 413  
 414          return true;
 415      }
 416  
 417      /**
 418       * We remove the featured field from the versioning
 419       *
 420       * @param   EventInterface  $event
 421       *
 422       * @return  boolean
 423       *
 424       * @since   4.0.0
 425       */
 426      public function onContentVersioningPrepareTable(EventInterface $event)
 427      {
 428          $subject = $event->getArgument('subject');
 429          $context = $event->getArgument('extension');
 430  
 431          if (!$this->isSupported($context)) {
 432              return true;
 433          }
 434  
 435          $parts = explode('.', $context);
 436  
 437          $component = $this->app->bootComponent($parts[0]);
 438  
 439          $modelName = $component->getModelName($context);
 440  
 441          $model = $component->getMVCFactory()->createModel($modelName, $this->app->getName(), ['ignore_request' => true]);
 442  
 443          $table = $model->getTable();
 444  
 445          $subject->ignoreChanges[] = $table->getColumnAlias('featured');
 446      }
 447  
 448      /**
 449       * Pre-processor for $table->store($updateNulls)
 450       *
 451       * @param   BeforeStoreEvent  $event  The event to handle
 452       *
 453       * @return  void
 454       *
 455       * @since   4.0.0
 456       */
 457      public function onTableBeforeStore(BeforeStoreEvent $event)
 458      {
 459          $subject = $event->getArgument('subject');
 460  
 461          if (!($subject instanceof ContentHistory)) {
 462              return;
 463          }
 464  
 465          $parts = explode('.', $subject->item_id);
 466  
 467          $typeAlias = $parts[0] . (isset($parts[1]) ? '.' . $parts[1] : '');
 468  
 469          if (!$this->isSupported($typeAlias)) {
 470              return;
 471          }
 472  
 473          $component = $this->app->bootComponent($parts[0]);
 474  
 475          $modelName = $component->getModelName($typeAlias);
 476  
 477          $model = $component->getMVCFactory()->createModel($modelName, $this->app->getName(), ['ignore_request' => true]);
 478  
 479          $table = $model->getTable();
 480  
 481          $field = $table->getColumnAlias('featured');
 482  
 483          $versionData = new Registry($subject->version_data);
 484  
 485          $versionData->remove($field);
 486  
 487          $subject->version_data = $versionData->toString();
 488      }
 489  
 490      /**
 491       * Check if the current plugin should execute workflow related activities
 492       *
 493       * @param   string  $context
 494       *
 495       * @return   boolean
 496       *
 497       * @since   4.0.0
 498       */
 499      protected function isSupported($context)
 500      {
 501          if (!$this->checkAllowedAndForbiddenlist($context) || !$this->checkExtensionSupport($context, $this->supportFunctionality)) {
 502              return false;
 503          }
 504  
 505          $parts = explode('.', $context);
 506  
 507          // We need at least the extension + view for loading the table fields
 508          if (count($parts) < 2) {
 509              return false;
 510          }
 511  
 512          $component = $this->app->bootComponent($parts[0]);
 513  
 514          if (
 515              !$component instanceof WorkflowServiceInterface
 516              || !$component->isWorkflowActive($context)
 517              || !$component->supportFunctionality($this->supportFunctionality, $context)
 518          ) {
 519              return false;
 520          }
 521  
 522          $modelName = $component->getModelName($context);
 523  
 524          $model = $component->getMVCFactory()->createModel($modelName, $this->app->getName(), ['ignore_request' => true]);
 525  
 526          if (!$model instanceof DatabaseModelInterface || !method_exists($model, 'featured')) {
 527              return false;
 528          }
 529  
 530          $table = $model->getTable();
 531  
 532          if (!$table instanceof TableInterface || !$table->hasField('featured')) {
 533              return false;
 534          }
 535  
 536          return true;
 537      }
 538  
 539      /**
 540       * If plugin supports the functionality we set the used variable
 541       *
 542       * @param   WorkflowFunctionalityUsedEvent  $event
 543       *
 544       * @since 4.0.0
 545       */
 546      public function onWorkflowFunctionalityUsed(WorkflowFunctionalityUsedEvent $event)
 547      {
 548          $functionality = $event->getArgument('functionality');
 549  
 550          if ($functionality !== 'core.featured') {
 551              return;
 552          }
 553  
 554          $event->setUsed();
 555      }
 556  }


Generated: Wed Sep 7 05:41:13 2022 Chilli.vc Blog - For Webmaster,Blog-Writer,System Admin and Domainer