You are here

class FocalPointPreviewController in Focal Point 8

Class FocalPointPreviewController.

@package Drupal\focal_point\Controller

Hierarchy

Expanded class hierarchy of FocalPointPreviewController

File

src/Controller/FocalPointPreviewController.php, line 25

Namespace

Drupal\focal_point\Controller
View source
class FocalPointPreviewController extends ControllerBase {

  /**
   * The image factory service.
   *
   * @var \Drupal\Core\Image\ImageFactory
   */
  protected $imageFactory;

  /**
   * The request service.
   *
   * @var \Symfony\Component\HttpFoundation\RequestStack
   */
  protected $request;

  /**
   * The file storage service.
   *
   * @var \Drupal\file\FileStorage
   */
  protected $fileStorage;

  /**
   * {@inheritdoc}
   *
   * @param \Drupal\Core\Image\ImageFactory $image_factory
   *   The image_factory parameter.
   * @param \Symfony\Component\HttpFoundation\RequestStack $request_stack
   *   The request parameter.
   */
  public function __construct(ImageFactory $image_factory, RequestStack $request_stack) {
    $this->imageFactory = $image_factory;
    $this->request = $request_stack
      ->getCurrentRequest();
    $this->fileStorage = $this
      ->entityTypeManager()
      ->getStorage('file');
  }

  /**
   * {@inheritdoc}
   */
  public static function create(ContainerInterface $container) {
    return new static($container
      ->get('image.factory'), $container
      ->get('request_stack'));
  }

  /**
   * {@inheritdoc}
   *
   * @throws \Symfony\Component\Validator\Exception\InvalidArgumentException
   */
  public function content($fid, $focal_point_value) {
    $output = [];
    $file = $this->fileStorage
      ->load($fid);
    $image = $this->imageFactory
      ->get($file
      ->getFileUri());
    if (!$image
      ->isValid()) {
      throw new InvalidArgumentException('The file with id = $fid is not an image.');
    }
    $styles = $this
      ->getFocalPointImageStyles();

    // Since we are about to create a new preview of this image, we first must
    // flush the old one. This should not be a performance hit since there is
    // no good reason for anyone to preview an image unless they are changing
    // the focal point value.
    image_path_flush($image
      ->getSource());
    $derivative_images = [];
    $derivative_image_note = '';
    $original_image = [
      '#theme' => 'image',
      '#uri' => $image
        ->getSource(),
      '#alt' => $this
        ->t('Focal Point Preview Image'),
      '#attributes' => [
        'id' => 'focal-point-preview-image',
      ],
    ];
    if (!empty($styles)) {
      foreach ($styles as $style) {
        $style_label = $style
          ->get('label');
        $url = $this
          ->buildUrl($style, $file, $focal_point_value);
        $derivative_images[$style
          ->getName()] = [
          'style' => $style_label,
          'url' => $url,
          'image' => [
            '#theme' => 'image',
            '#uri' => $url,
            '#alt' => $this
              ->t('Focal Point Preview: %label', [
              '%label' => $style_label,
            ]),
            '#attributes' => [
              'class' => [
                'focal-point-derivative-preview-image',
              ],
            ],
          ],
        ];
      }
      $derivative_image_note = $this
        ->t('Click an image to see a larger preview. You may need to scroll horizontally for more image styles.');
    }
    else {

      // There are no styles that use a focal point effect to preview.
      $image_styles_url = Url::fromRoute('entity.image_style.collection')
        ->toString();
      $this
        ->messenger()
        ->addWarning($this
        ->t('You must have at least one <a href=":url">image style</a> defined that uses a focal point effect in order to preview.', [
        ':url' => $image_styles_url,
      ]));
    }
    $output['focal_point_preview_page'] = [
      '#theme' => "focal_point_preview_page",
      "#original_image" => $original_image,
      '#derivative_images' => $derivative_images,
      '#focal_point' => $focal_point_value,
      '#preview_image_note' => $this
        ->t('This preview image above may have been scaled to fit on the page.'),
      '#derivative_image_note' => $derivative_image_note,
    ];
    $options = [
      'dialogClass' => 'popup-dialog-class',
      'width' => '80%',
    ];
    $response = new AjaxResponse();
    $response
      ->addCommand(new OpenModalDialogCommand($this
      ->t('Images preview'), $output, $options));
    return $response;
  }

  /**
   * Define access control for the preview page.
   *
   * Deny users access to the preview page unless they have permission to edit
   * an entity (any entity) that references the current image being previewed or
   * if they've provide a valid token as a query string. The later is needed so
   * preview will work when creating a new entity that has not yet been saved.
   *
   * @param \Drupal\Core\Session\AccountInterface $account
   *   The current user.
   * @param int $fid
   *   The file id for the image being previewed from the URL.
   *
   * @return \Drupal\Core\Access\AccessResult
   *   An AccessResult object defining if permission is granted or not.
   */
  public function access(AccountInterface $account, $fid) {
    $access = AccessResult::forbidden();

    // @todo: I should be able to use "magic args" to load the file directly.
    $file = $this->fileStorage
      ->load($fid);
    $image = $this->imageFactory
      ->get($file
      ->getFileUri());
    if (!$image
      ->isValid()) {
      throw new InvalidArgumentException('The file with id = $fid is not an image.');
    }

    // Check if there was a valid token provided in with the HTTP request so
    // that preview is available on a "create entity" form.
    if ($this
      ->validTokenProvided()) {
      $access = AccessResult::allowed();
    }

    // If access has not yet been granted and the file module is enabled, check
    // if there is an entity that references this file which the current user
    // has access to edit.
    if (function_exists('file_get_file_references') && !$access
      ->isAllowed()) {
      $references = file_get_file_references($file, NULL, EntityStorageInterface::FIELD_LOAD_REVISION, '');
      foreach ($references as $data) {
        foreach (array_keys($data) as $entity_type_id) {
          if ($account
            ->hasPermission($entity_type_id . ".edit")) {
            $access = AccessResult::allowed();
            break;
          }
        }
      }
    }
    return $access;
  }

  /**
   * Build a list of image styles that include an effect defined by focal point.
   *
   * @return array
   *   An array of machine names of image styles that use a focal point effect.
   */
  public function getFocalPointImageStyles() {

    // @todo: Can this be generated? See $imageEffectManager->getDefinitions();
    $focal_point_effects = [
      'focal_point_crop',
      'focal_point_scale_and_crop',
    ];
    $styles_using_focal_point = [];
    $styles = $this
      ->entityTypeManager()
      ->getStorage('image_style')
      ->loadMultiple();
    foreach ($styles as $image_style_id => $style) {
      foreach ($style
        ->getEffects() as $effect) {
        $style_using_focal_point = in_array($effect
          ->getPluginId(), $focal_point_effects, TRUE);
        if ($style_using_focal_point) {
          $styles_using_focal_point[$image_style_id] = $style;
          break;
        }
      }
    }
    return $styles_using_focal_point;
  }

  /**
   * Create the URL for a preview image including a query parameter.
   *
   * @param \Drupal\image\ImageStyleInterface $style
   *   The image style being previewed.
   * @param \Drupal\file\Entity\File $image
   *   The image being previewed.
   * @param string $focal_point_value
   *   The focal point being previewed in the format XxY where x and y are the
   *   left and top offsets in percentages.
   *
   * @return \Drupal\Core\GeneratedUrl|string
   *   The URL of the preview image.
   */
  protected function buildUrl(ImageStyleInterface $style, File $image, $focal_point_value) {
    $url = $style
      ->buildUrl($image
      ->getFileUri());
    $url .= (strpos($url, '?') !== FALSE ? '&' : '?') . 'focal_point_preview_value=' . $focal_point_value;
    return $url;
  }

  /**
   * Was a valid token found?
   *
   * Determine if a valid focal point token was provided in the query string of
   * the current request. If no token is provided in the query string then this
   * method will return FALSE.
   *
   * @return bool
   *   Indicates if a valid token was provided in the query string.
   */
  protected function validTokenProvided() {
    try {
      if (\Drupal::request()->query
        ->has('focal_point_token')) {
        $token = \Drupal::request()->query
          ->get('focal_point_token');
        return FocalPointImageWidget::validatePreviewToken($token);
      }
      else {
        return FALSE;
      }
    } catch (\InvalidArgumentException $e) {
      return FALSE;
    }
  }

}

Members

Namesort descending Modifiers Type Description Overrides
ControllerBase::$configFactory protected property The configuration factory.
ControllerBase::$currentUser protected property The current user service. 1
ControllerBase::$entityFormBuilder protected property The entity form builder.
ControllerBase::$entityManager protected property The entity manager.
ControllerBase::$entityTypeManager protected property The entity type manager.
ControllerBase::$formBuilder protected property The form builder. 2
ControllerBase::$keyValue protected property The key-value storage. 1
ControllerBase::$languageManager protected property The language manager. 1
ControllerBase::$moduleHandler protected property The module handler. 2
ControllerBase::$stateService protected property The state service.
ControllerBase::cache protected function Returns the requested cache bin.
ControllerBase::config protected function Retrieves a configuration object.
ControllerBase::container private function Returns the service container.
ControllerBase::currentUser protected function Returns the current user. 1
ControllerBase::entityFormBuilder protected function Retrieves the entity form builder.
ControllerBase::entityManager Deprecated protected function Retrieves the entity manager service.
ControllerBase::entityTypeManager protected function Retrieves the entity type manager.
ControllerBase::formBuilder protected function Returns the form builder service. 2
ControllerBase::keyValue protected function Returns a key/value storage collection. 1
ControllerBase::languageManager protected function Returns the language manager service. 1
ControllerBase::moduleHandler protected function Returns the module handler. 2
ControllerBase::redirect protected function Returns a redirect response object for the specified route. Overrides UrlGeneratorTrait::redirect
ControllerBase::state protected function Returns the state storage service.
FocalPointPreviewController::$fileStorage protected property The file storage service.
FocalPointPreviewController::$imageFactory protected property The image factory service.
FocalPointPreviewController::$request protected property The request service.
FocalPointPreviewController::access public function Define access control for the preview page.
FocalPointPreviewController::buildUrl protected function Create the URL for a preview image including a query parameter.
FocalPointPreviewController::content public function
FocalPointPreviewController::create public static function Instantiates a new instance of this class. Overrides ControllerBase::create
FocalPointPreviewController::getFocalPointImageStyles public function Build a list of image styles that include an effect defined by focal point.
FocalPointPreviewController::validTokenProvided protected function Was a valid token found?
FocalPointPreviewController::__construct public function
LinkGeneratorTrait::$linkGenerator protected property The link generator. 1
LinkGeneratorTrait::getLinkGenerator Deprecated protected function Returns the link generator.
LinkGeneratorTrait::l Deprecated protected function Renders a link to a route given a route name and its parameters.
LinkGeneratorTrait::setLinkGenerator Deprecated public function Sets the link generator service.
LoggerChannelTrait::$loggerFactory protected property The logger channel factory service.
LoggerChannelTrait::getLogger protected function Gets the logger for a specific channel.
LoggerChannelTrait::setLoggerFactory public function Injects the logger channel factory.
MessengerTrait::$messenger protected property The messenger. 29
MessengerTrait::messenger public function Gets the messenger. 29
MessengerTrait::setMessenger public function Sets the messenger.
RedirectDestinationTrait::$redirectDestination protected property The redirect destination service. 1
RedirectDestinationTrait::getDestinationArray protected function Prepares a 'destination' URL query parameter for use with \Drupal\Core\Url.
RedirectDestinationTrait::getRedirectDestination protected function Returns the redirect destination service.
RedirectDestinationTrait::setRedirectDestination public function Sets the redirect destination service.
StringTranslationTrait::$stringTranslation protected property The string translation service. 1
StringTranslationTrait::formatPlural protected function Formats a string containing a count of items.
StringTranslationTrait::getNumberOfPlurals protected function Returns the number of plurals supported by a given language.
StringTranslationTrait::getStringTranslation protected function Gets the string translation service.
StringTranslationTrait::setStringTranslation public function Sets the string translation service to use. 2
StringTranslationTrait::t protected function Translates a string to the current language or to a given language.
UrlGeneratorTrait::$urlGenerator protected property The url generator.
UrlGeneratorTrait::getUrlGenerator Deprecated protected function Returns the URL generator service.
UrlGeneratorTrait::setUrlGenerator Deprecated public function Sets the URL generator service.
UrlGeneratorTrait::url Deprecated protected function Generates a URL or path for a specific route based on the given parameters.