editorjs-2.x-dev/src/Controller/ImageController.php

src/Controller/ImageController.php
<?php

namespace Drupal\editorjs\Controller;

use Drupal\Component\Serialization\Json;
use Drupal\Component\Utility\Bytes;
use Drupal\Component\Utility\Environment;
use Drupal\Component\Utility\UrlHelper;
use Drupal\Core\Config\ConfigFactoryInterface;
use Drupal\Core\DependencyInjection\ContainerInjectionInterface;
use Drupal\Core\Entity\EntityRepositoryInterface;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\File\Exception\FileException;
use Drupal\Core\File\FileSystemInterface;
use Drupal\Core\Logger\LoggerChannelFactoryInterface;
use Drupal\Core\Messenger\MessengerInterface;
use Drupal\Core\Session\AccountProxyInterface;
use Drupal\Core\StreamWrapper\StreamWrapperManagerInterface;
use Drupal\Core\StringTranslation\StringTranslationTrait;
use Drupal\Core\Utility\Token;
use Drupal\file\Entity\File;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;

/**
 * Defines controller for image plugin.
 *
 * @see https://github.com/batkor/editorjs-dimage
 */
final class ImageController implements ContainerInjectionInterface {

  use StringTranslationTrait;

  /**
   * The file system manager.
   *
   * @var \Drupal\Core\File\FileSystemInterface
   */
  protected $fileSystem;

  /**
   * The account proxy.
   *
   * @var \Drupal\Core\Session\AccountProxyInterface
   */
  protected $accountProxy;

  /**
   * The entity repository.
   *
   * @var \Drupal\Core\Entity\EntityRepositoryInterface
   */
  protected $entityRepository;

  /**
   * The entity type manager.
   *
   * @var \Drupal\Core\Entity\EntityTypeManagerInterface
   */
  protected $entityTypeManager;

  /**
   * The stream wrapper manager.
   *
   * @var \Drupal\Core\StreamWrapper\StreamWrapperManagerInterface
   */
  protected $streamWrapperManager;

  /**
   * The config factory.
   *
   * @var \Drupal\Core\Config\ConfigFactoryInterface
   */
  protected $configFactory;

  /**
   * The logger factory.
   *
   * @var \Drupal\Core\Logger\LoggerChannelFactoryInterface
   */
  protected $loggerChannelFactory;

  /**
   * The messenger.
   *
   * @var \Drupal\Core\Messenger\MessengerInterface
   */
  protected $messenger;

  /**
   * The token system.
   *
   * @var \Drupal\Core\Utility\Token
   */
  protected $token;

  /**
   * ImageController constructor.
   *
   * @param \Drupal\Core\File\FileSystemInterface $fileSystem
   *   The file system manager.
   * @param \Drupal\Core\Session\AccountProxyInterface $accountProxy
   *   The account proxy.
   * @param \Drupal\Core\Entity\EntityRepositoryInterface $entityRepository
   *   The entity repository.
   * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entityTypeManager
   *   The entity type manager.
   * @param \Drupal\Core\StreamWrapper\StreamWrapperManagerInterface $streamWrapperManager
   *   The stream wrapper manager.
   * @param \Drupal\Core\Config\ConfigFactoryInterface $configFactory
   *   The config factory.
   * @param \Drupal\Core\Logger\LoggerChannelFactoryInterface $loggerChannelFactory
   *   The logger factory.
   * @param \Drupal\Core\Messenger\MessengerInterface $messenger
   *   The messenger.
   * @param \Drupal\Core\Utility\Token $token
   *   The token system.
   */
  public function __construct(
    FileSystemInterface $fileSystem,
    AccountProxyInterface $accountProxy,
    EntityRepositoryInterface $entityRepository,
    EntityTypeManagerInterface $entityTypeManager,
    StreamWrapperManagerInterface $streamWrapperManager,
    ConfigFactoryInterface $configFactory,
    LoggerChannelFactoryInterface $loggerChannelFactory,
    MessengerInterface $messenger,
    Token $token
  ) {
    $this->fileSystem = $fileSystem;
    $this->accountProxy = $accountProxy;
    $this->entityRepository = $entityRepository;
    $this->entityTypeManager = $entityTypeManager;
    $this->streamWrapperManager = $streamWrapperManager;
    $this->configFactory = $configFactory;
    $this->loggerChannelFactory = $loggerChannelFactory;
    $this->messenger = $messenger;
    $this->token = $token;
  }

  /**
   * {@inheritdoc}
   */
  public static function create(ContainerInterface $container) {
    return new static(
      $container->get('file_system'),
      $container->get('current_user'),
      $container->get('entity.repository'),
      $container->get('entity_type.manager'),
      $container->get('stream_wrapper_manager'),
      $container->get('config.factory'),
      $container->get('logger.factory'),
      $container->get('messenger'),
      $container->get('token')
    );
  }

  /**
   * Response for image upload.
   *
   * @param \Symfony\Component\HttpFoundation\Request $request
   *   The request.
   *
   * @return \Symfony\Component\HttpFoundation\JsonResponse
   *   The response.
   *
   * @throws \Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException
   * @throws \Drupal\Component\Plugin\Exception\PluginNotFoundException
   * @throws \Drupal\Core\Entity\EntityStorageException
   */
  public function upload(Request $request): JsonResponse {
    /** @var \Symfony\Component\HttpFoundation\File\UploadedFile $uploadFile */
    $uploadFile = $request->files->get('image');
    if (!$uploadFile) {
      throw new BadRequestHttpException();
    }

    // There is always a file size limit due to the PHP server limit.
    $validators = [
      'file_validate_extensions' => [$this->allowExtension($request)],
      'file_validate_size' => [Bytes::toInt(Environment::getUploadMaxSize())],
    ];
    $directory = trim($request->headers->get('x-directory', ''), '/');
    if (!empty($directory)) {
      $directory .= '/';
    }
    $data = file_get_contents($uploadFile->getRealPath());
    $file = $this->saveData($data, 'public://' . $directory . $uploadFile->getClientOriginalName(), $validators);
    if (!$file) {
      return new JsonResponse(['success' => FALSE]);
    }
    $result = [
      'success' => TRUE,
      'file' => [
        'url' => $file->createFileUrl(FALSE),
        'uuid' => $file->uuid(),
      ],
    ];
    return new JsonResponse($result);
  }

  /**
   * Response for image upload by url.
   *
   * @param \Symfony\Component\HttpFoundation\Request $request
   *   The request.
   *
   * @return \Symfony\Component\HttpFoundation\JsonResponse
   *   The response.
   *
   * @throws \Drupal\Core\Entity\EntityStorageException
   */
  public function uploadUrl(Request $request): JsonResponse {
    $data = Json::decode($request->getContent());
    if (empty($data['url'])) {
      throw new BadRequestHttpException();
    }
    $url = $data['url'];
    $data = file_get_contents($url);
    if ($data == FALSE) {
      return new JsonResponse(['success' => FALSE]);
    }

    $validators = [
      'file_validate_extensions' => [$this->allowExtension($request)],
      'file_validate_size' => [Bytes::toInt(Environment::getUploadMaxSize())],
    ];
    $directory = trim($request->headers->get('x-directory', ''), '/');
    if (!empty($directory)) {
      $directory .= '/';
    }
    $parsed_url = UrlHelper::parse($url);
    $destination = "public://$directory";
    $destination .= basename($parsed_url['path']);
    $file = $this->saveData($data, $destination, $validators);
    if (!$file) {
      return new JsonResponse(['success' => FALSE]);
    }

    $result = [
      'success' => TRUE,
      'file' => [
        'url' => $file->createFileUrl(FALSE),
        'uuid' => $file->uuid(),
      ],
    ];

    return new JsonResponse($result);
  }

  /**
   * Response for generate image style url.
   *
   * @param \Symfony\Component\HttpFoundation\Request $request
   *   The request.
   *
   * @return \Symfony\Component\HttpFoundation\JsonResponse
   *   The response.
   */
  public function styleUrl(Request $request): JsonResponse {
    $data = Json::decode($request->getContent());

    /** @var \Drupal\file\Entity\File $file */
    $file = $this->entityRepository
      ->loadEntityByUuid('file', $data['uuid']);
    if (!$file) {
      throw new BadRequestHttpException('File not found.');
    }
    if (empty($data['image_style_id'])) {
      return new JsonResponse(['url' => $file->createFileUrl()]);
    }
    /** @var \Drupal\image\Entity\ImageStyle $image_style */
    $image_style = $this
      ->entityTypeManager
      ->getStorage('image_style')
      ->load($data['image_style_id']);
    if (!$image_style) {
      throw new BadRequestHttpException('Image style not found.');
    }

    $url = $image_style->buildUrl($file->getFileUri());

    return new JsonResponse(['url' => $url]);
  }

  /**
   * Returns file entity after save.
   *
   * @param string $data
   *   A string containing the contents of the file.
   * @param string $destination
   *   A string containing the destination URI.
   * @param array $validators
   *   The callback list for validate.
   * @param int $replace
   *   The replace behavior when the destination file already exists.
   *
   * @return \Drupal\file\FileInterface|false
   *   The file entity elsa false.
   *
   * @throws \Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException
   * @throws \Drupal\Component\Plugin\Exception\PluginNotFoundException
   * @throws \Drupal\Core\Entity\EntityStorageException
   */
  protected function saveData($data, $destination, array $validators = [], $replace = FileSystemInterface::EXISTS_REPLACE) {
    if (empty($destination)) {
      $destination = $this->configFactory->get('system.file')->get('default_scheme') . '://';
    }
    $destination = $this->token->replace($destination, [], ['clear' => TRUE]);
    if (!$this->streamWrapperManager->isValidUri($destination)) {
      $this->loggerChannelFactory->get('file')->notice('The data could not be saved because the destination %destination is invalid. This may be caused by improper use of file_save_data() or a missing stream wrapper.', ['%destination' => $destination]);
      $this->messenger->addError($this->t('The data could not be saved because the destination is invalid. More information is available in the system log.'));
      return FALSE;
    }

    try {
      $dir = $this->fileSystem->dirname($destination);
      $this->fileSystem->prepareDirectory($dir, FileSystemInterface::CREATE_DIRECTORY);
      $uri = $this->fileSystem->saveData($data, $destination, $replace);
      /** @var \Drupal\file\Entity\File $file */
      $file = File::create([
        'uri' => $uri,
        'uid' => $this->accountProxy->id(),
        'status' => 0,
      ]);
      // If we are replacing an existing file re-use its database record.
      // @todo Do not create a new entity in order to update it. See
      //   https://www.drupal.org/node/2241865.
      if ($replace == FileSystemInterface::EXISTS_REPLACE) {
        $existing_files = $this->entityTypeManager->getStorage('file')->loadByProperties(['uri' => $uri]);
        if (count($existing_files)) {
          $existing = reset($existing_files);
          $file->fid = $existing->id();
          $file->set('uuid', $existing->uuid());
          $file->setOriginalId($existing->id());
          $file->setFilename($existing->getFilename());
        }
      }
      // If we are renaming around an existing file (rather than a directory),
      // use its basename for the filename.
      elseif ($replace == FileSystemInterface::EXISTS_RENAME && is_file($destination)) {
        $file->setFilename($this->fileSystem->basename($destination));
      }

      $errors = file_validate($file, $validators);
      if (!empty($errors)) {
        foreach ($errors as $error) {
          $this->messenger->addError($error);
        }
        return FALSE;
      }
      $file->save();
      return $file;
    }
    catch (FileException $e) {
      return FALSE;
    }
  }

  /**
   * Returns allow extension from request.
   *
   * @param \Symfony\Component\HttpFoundation\Request $request
   *   The request.
   *
   * @return string
   *   The allow extensions list.
   */
  protected function allowExtension(Request $request) {
    return $request->headers->get('allow-extensions', 'png gif jpg jpeg');
  }

}

Главная | Обратная связь

drupal hosting | друпал хостинг | it patrol .inc