diff --git a/src/CropInterface.php b/src/CropInterface.php index 7b2ef28..2098846 100644 --- a/src/CropInterface.php +++ b/src/CropInterface.php @@ -22,6 +22,19 @@ interface CropInterface extends ContentEntityInterface { public function position(); /** + * Sets position of crop's center. + * + * @param int $x + * X coordinate of the crop's center. + * @param int $y + * Y coordinate of the crop's center. + * + * @return \Drupal\crop\CropInterface + * Crop object this is being called on. + */ + public function setPosition($x, $y); + + /** * Gets crop's size. * * @return array @@ -30,6 +43,19 @@ interface CropInterface extends ContentEntityInterface { public function size(); /** + * Sets crop's size. + * + * @param int $width + * Crop's width. + * @param int $height + * Crop's height. + * + * @return \Drupal\crop\CropInterface + * Crop object this is being called on. + */ + public function setSize($width, $height); + + /** * Gets crop anchor (top-left corner of crop area). * * @return array @@ -48,4 +74,31 @@ interface CropInterface extends ContentEntityInterface { */ public function provider(); + /** + * Checks whether crop exists for an image. + * + * @param string $uri + * URI of image to check for. + * @param string $type + * (Optional) Type of crop. Function will check across all available types + * if ommitted. + * + * @return bool + * Boolean TRUE if crop exists and FALSE if not. + */ + public static function cropExists($uri, $type = NULL); + + /** + * Loads crop based on image URI and crop type. + * + * @param string $uri + * URI of the image. + * @param string $type + * Crop type. + * + * @return \Drupal\crop\CropInterface|null + * Crop entity or NULL if crop doesn't exist. + */ + public static function findCrop($uri, $type); + } diff --git a/src/Entity/Crop.php b/src/Entity/Crop.php index e6aed7e..98c9f35 100644 --- a/src/Entity/Crop.php +++ b/src/Entity/Crop.php @@ -60,18 +60,28 @@ class Crop extends ContentEntityBase implements CropInterface { */ public function position() { return [ - 'x' => $this->x->value, - 'y' => $this->y->value, + 'x' => (int) $this->x->value, + 'y' => (int) $this->y->value, ]; } /** * {@inheritdoc} */ + public function setPosition($x, $y) { + $this->x = $x; + $this->y = $y; + + return $this; + } + + /** + * {@inheritdoc} + */ public function anchor() { return [ - 'x' => $this->x->value - ($this->width->value / 2), - 'y' => $this->y->value - ($this->height->value / 2), + 'x' => (int) ($this->x->value - ($this->width->value / 2)), + 'y' => (int) ($this->y->value - ($this->height->value / 2)), ]; } @@ -80,14 +90,23 @@ class Crop extends ContentEntityBase implements CropInterface { */ public function size() { return [ - 'width' => $this->width->value, - 'height' => $this->height->value, + 'width' => (int) $this->width->value, + 'height' => (int) $this->height->value, ]; } /** * {@inheritdoc} */ + public function setSize($width, $height) { + $this->width = $width; + $this->height = $height; + return $this; + } + + /** + * {@inheritdoc} + */ public function provider() { /** @var \Drupal\crop\EntityProviderManager $plugin_manager */ $plugin_manager = \Drupal::service('plugin.manager.crop.entity_provider'); @@ -102,6 +121,34 @@ class Crop extends ContentEntityBase implements CropInterface { /** * {@inheritdoc} */ + public static function cropExists($uri, $type = NULL) { + $query = \Drupal::entityQuery('crop') + ->condition('uri', $uri); + if ($type) { + $query->condition('type', $type); + } + return (bool) $query->execute(); + } + + /** + * {@inheritdoc} + */ + public static function findCrop($uri, $type) { + $query = \Drupal::entityQuery('crop') + ->condition('uri', $uri); + if ($type) { + $query->condition('type', $type); + } + $crop = $query->sort('cid') + ->range(0, 1) + ->execute(); + + return $crop ? \Drupal::entityTypeManager()->getStorage('crop')->load(current($crop)) : NULL; + } + + /** + * {@inheritdoc} + */ public function preSave(EntityStorageInterface $storage) { parent::preSave($storage); @@ -138,6 +185,14 @@ class Crop extends ContentEntityBase implements CropInterface { /** * {@inheritdoc} */ + public function save() { + parent::save(); + image_path_flush($this->uri->value); + } + + /** + * {@inheritdoc} + */ public static function baseFieldDefinitions(EntityTypeInterface $entity_type) { $fields = []; diff --git a/src/Plugin/ImageEffect/CropEffect.php b/src/Plugin/ImageEffect/CropEffect.php index c2aac16..2dbf8f4 100644 --- a/src/Plugin/ImageEffect/CropEffect.php +++ b/src/Plugin/ImageEffect/CropEffect.php @@ -12,6 +12,7 @@ use Drupal\Core\Form\FormStateInterface; use Drupal\Core\Image\ImageInterface; use Drupal\Core\Plugin\ContainerFactoryPluginInterface; use Drupal\crop\CropStorageInterface; +use Drupal\crop\Entity\Crop; use Drupal\image\ConfigurableImageEffectBase; use Psr\Log\LoggerInterface; use Symfony\Component\DependencyInjection\ContainerInterface; @@ -162,15 +163,7 @@ class CropEffect extends ConfigurableImageEffectBase implements ContainerFactory protected function getCrop(ImageInterface $image) { if (!isset($this->crop)) { $this->crop = FALSE; - - $id = $this->storage->getQuery() - ->condition('uri', $image->getSource()) - ->condition('type', $this->configuration['crop_type']) - ->sort('cid') - ->range(0, 1) - ->execute(); - - if (!empty($id) && ($crop = $this->storage->load(current($id)))) { + if ($crop = Crop::findCrop($image->getSource(), $this->configuration['crop_type'])) { $this->crop = $crop; } } diff --git a/src/Tests/CropCRUDTest.php b/src/Tests/CropCRUDTest.php index d200bc7..fdcfecb 100644 --- a/src/Tests/CropCRUDTest.php +++ b/src/Tests/CropCRUDTest.php @@ -7,7 +7,8 @@ namespace Drupal\crop\Tests; -use Drupal\Component\Utility\SafeMarkup; +use Drupal\Component\Render\FormattableMarkup; +use Drupal\crop\Entity\Crop; /** * Tests the crop entity CRUD operations. @@ -44,7 +45,7 @@ class CropCRUDTest extends CropUnitTestBase { $loaded = $this->container->get('config.factory')->get('crop.type.' . $values['id'])->get(); foreach ($values as $key => $value) { - $this->assertEqual($loaded[$key], $value, SafeMarkup::format('Correct value for @field found.', ['@field' => $key])); + $this->assertEqual($loaded[$key], $value, new FormattableMarkup('Correct value for @field found.', ['@field' => $key])); } } @@ -61,6 +62,7 @@ class CropCRUDTest extends CropUnitTestBase { 'type' => $this->cropType->id(), 'entity_id' => $file->id(), 'entity_type' => $file->getEntityTypeId(), + 'uri' => $file->getFileUri(), 'x' => '100', 'y' => '150', 'width' => '200', @@ -68,6 +70,20 @@ class CropCRUDTest extends CropUnitTestBase { ]; $crop = $this->cropStorage->create($values); + $this->assertEquals(['x' => 100, 'y' => 150], $crop->position(), t('Position correctly returned.')); + $this->assertEquals(['width' => 200, 'height' => 250], $crop->size(), t('Size correctly returned.')); + $this->assertEquals(['x' => 0, 'y' => 25], $crop->anchor(), t('Anchor correctly returned.')); + + $crop->setPosition(10, 10); + $crop->setSize(20, 20); + + $this->assertEquals(['x' => 10, 'y' => 10], $crop->position(), t('Position correctly returned.')); + $this->assertEquals(['width' => 20, 'height' => 20], $crop->size(), t('Size correctly returned.')); + $this->assertEquals(['x' => 0, 'y' => 0], $crop->anchor(), t('Anchor correctly returned.')); + + $crop->setPosition($values['x'], $values['y']); + $crop->setSize($values['width'], $values['height']); + try { $crop->save(); $this->assertTrue(TRUE, 'Crop saved correctly.'); @@ -80,15 +96,27 @@ class CropCRUDTest extends CropUnitTestBase { foreach ($values as $key => $value) { switch ($key) { case 'type': - $this->assertEqual($loaded_crop->{$key}->target_id, $value, SafeMarkup::format('Correct value for @field found.', ['@field' => $key])); + $this->assertEqual($loaded_crop->{$key}->target_id, $value, new FormattableMarkup('Correct value for @field found.', ['@field' => $key])); break; default: - $this->assertEqual($loaded_crop->{$key}->value, $value, SafeMarkup::format('Correct value for @field found.', ['@field' => $key])); + $this->assertEqual($loaded_crop->{$key}->value, $value, new FormattableMarkup('Correct value for @field found.', ['@field' => $key])); break; } } + $this->assertTrue(Crop::cropExists($file->getFileUri()), t('Crop::cropExists() correctly found saved crop.')); + $this->assertTrue(Crop::cropExists($file->getFileUri(), $this->cropType->id()), t('Crop::cropExists() correctly found saved crop.')); + $this->assertFalse(Crop::cropExists($file->getFileUri(), 'nonexistent_type'), t('Crop::cropExists() correctly handled wrong type.')); + $this->assertFalse(Crop::cropExists('public://nonexistent.png'), t('Crop::cropExists() correctly handled wrong uri.')); + + $loaded_crop = Crop::findCrop($file->getFileUri(), $this->cropType->id()); + $this->assertEquals($crop->id(), $loaded_crop->id(), t('Crop::findCrop() correctly loaded crop entity.')); + $this->assertEquals($crop->position(), $loaded_crop->position(), t('Crop::findCrop() correctly loaded crop entity.')); + $this->assertEquals($crop->size(), $loaded_crop->size(), t('Crop::findCrop() correctly loaded crop entity.')); + $this->assertEquals($crop->uri->value, $loaded_crop->uri->value, t('Crop::findCrop() correctly loaded crop entity.')); + $this->assertNull(Crop::findCrop('public://nonexistent.png', $this->cropType->id()), t('Crop::findCrop() correctly handled nonexistent crop.')); + $this->assertNull(Crop::findCrop('public://nonexistent.png', 'nonexistent_crop'), t('Crop::findCrop() correctly handled nonexistent crop.')); } }