From 3ec1db06931bf15fa4936d25210ef3859d107ed6 Mon Sep 17 00:00:00 2001 From: Benjamin Mack <benni@typo3.org> Date: Sun, 21 Jun 2015 15:47:51 +0200 Subject: [PATCH] [FEATURE] Introduce DataProcessor for media galleries The logic for working with galleries and calculating the maximum media size is done in a separate galleryProcessor. Resolves: #67663 Releases: master Change-Id: If00c3b800b2c6723d923cb3e3d427b850f9be7fe Reviewed-on: http://review.typo3.org/40509 Reviewed-by: Frans Saris <franssaris@gmail.com> Tested-by: Frans Saris <franssaris@gmail.com> Reviewed-by: Georg Ringer <georg.ringer@gmail.com> Tested-by: Georg Ringer <georg.ringer@gmail.com> Reviewed-by: Patrick Broens <patrick@patrickbroens.nl> Tested-by: Patrick Broens <patrick@patrickbroens.nl> --- ...ntroduceDataProcessorForMediaGalleries.rst | 64 +++ .../DataProcessing/GalleryProcessor.php | 492 ++++++++++++++++++ .../Unit/Processor/GalleryProcessorTest.php | 460 ++++++++++++++++ 3 files changed, 1016 insertions(+) create mode 100644 typo3/sysext/core/Documentation/Changelog/master/Feature-67663-IntroduceDataProcessorForMediaGalleries.rst create mode 100644 typo3/sysext/frontend/Classes/DataProcessing/GalleryProcessor.php create mode 100644 typo3/sysext/frontend/Tests/Unit/Processor/GalleryProcessorTest.php diff --git a/typo3/sysext/core/Documentation/Changelog/master/Feature-67663-IntroduceDataProcessorForMediaGalleries.rst b/typo3/sysext/core/Documentation/Changelog/master/Feature-67663-IntroduceDataProcessorForMediaGalleries.rst new file mode 100644 index 000000000000..22db04de86a1 --- /dev/null +++ b/typo3/sysext/core/Documentation/Changelog/master/Feature-67663-IntroduceDataProcessorForMediaGalleries.rst @@ -0,0 +1,64 @@ +============================================================= +Feature: #67663 - Introduce DataProcessor for media galleries +============================================================= + +Description +=========== + +The logic for working with galleries and calculating the maximum asset size is done in a separate GalleryProcessor. +The GalleryProcessor uses the files already present in the processedData array for his calculations. The FilesProcessor can be used to fetch the files. + +.. code-block:: typoscript + + tt_content.text_media.20 = FLUIDTEMPLATE + tt_content.image.20 { + file = EXT:myextension/Resources/Private/Templates/ContentObjects/Image.html + + dataProcessing { + + # Process files + 10 = TYPO3\CMS\Frontend\DataProcessing\FilesProcessor + + # Calculate gallery info + 20 = TYPO3\CMS\Frontend\DataProcessing\GalleryProcessor + 20 { + + # filesProcessedDataKey :: Key in processedData array that holds the files (default: files) + stdWrap + filesProcessedDataKey = files + + # mediaOrientation :: Media orientation, see: TCA[tt_content][column][imageorient] (default: data.imageorient) + stdWrap + mediaOrientation.field = imageorient + + # numberOfColumns :: Number of columns (default: data.imagecols) + stdWrap + numberOfColumns.field = imagecols + + # equalMediaHeight :: Equal media height in pixels (default: data.imageheight) + stdWrap + equalMediaHeight.field = imageheight + + # equalMediaWidth :: Equal media width in pixels (default: data.imagewidth) + stdWrap + equalMediaWidth.field = imagewidth + + # maxGalleryWidth :: Max gallery width in pixels (default: 600) + stdWrap + maxGalleryWidth = 1000 + + # maxGalleryWidthInText :: Max gallery width in pixels when orientation intext (default: 300) + stdWrap + maxGalleryWidthInText = 1000 + + # columnSpacing :: Column spacing width in pixels (default: 0) + stdWrap + columnSpacing = 0 + + # borderEnabled :: Border enabled (default: data.imageborder) + stdWrap + borderEnabled.field = imageborder + + # borderWidth :: Border width in pixels (default: 0) + stdWrap + borderWidth = 0 + + # borderPadding :: Border padding in pixels (default: 0) + stdWrap + borderPadding = 10 + + # as :: Name of key in processedData array where result is placed (default: gallery) + stdWrap + as = gallery + } + } + + } \ No newline at end of file diff --git a/typo3/sysext/frontend/Classes/DataProcessing/GalleryProcessor.php b/typo3/sysext/frontend/Classes/DataProcessing/GalleryProcessor.php new file mode 100644 index 000000000000..5c4765f52abd --- /dev/null +++ b/typo3/sysext/frontend/Classes/DataProcessing/GalleryProcessor.php @@ -0,0 +1,492 @@ +<?php +namespace TYPO3\CMS\Frontend\DataProcessing; + +/* + * This file is part of the TYPO3 CMS project. + * + * It is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License, either version 2 + * of the License, or any later version. + * + * For the full copyright and license information, please read the + * LICENSE.txt file that was distributed with this source code. + * + * The TYPO3 project - inspiring people to share! + */ + +use TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer; +use TYPO3\CMS\Frontend\ContentObject\DataProcessorInterface; +use TYPO3\CMS\Frontend\ContentObject\Exception\ContentRenderingException; + +/** + * This data processor will calculate rows, columns and dimensions for a gallery + * based on several settings and can be used for f.i. the CType "textmedia" + * + * The output will be an array which contains the rows and columns, + * including the file references and the calculated width and height for each media element, + * but also some more information of the gallery, like position, width and counters + * + * Example TypoScript configuration: + * + * 10 = TYPO3\CMS\Frontend\DataProcessing\GalleryProcessor + * 10 { + * filesProcessedDataKey = files + * mediaOrientation.field = imageorient + * numberOfColumns.field = imagecols + * equalMediaHeight.field = imageheight + * equalMediaWidth.field = imagewidth + * columnSpacing = 0 + * borderEnabled.field = imageborder + * borderPadding = 0 + * borderWidth = 0 + * maxGalleryWidth = {$styles.content.imgtext.maxW} + * maxGalleryWidthInText = {$styles.content.imgtext.maxWInText} + * as = gallery + * } + * + * Output example: + * + * gallery { + * position { + * horizontal = center + * vertical = above + * noWrap = FALSE + * } + * width = 600 + * count { + * files = 2 + * columns = 1 + * rows = 2 + * } + * rows { + * 1 { + * columns { + * 1 { + * media = TYPO3\CMS\Core\Resource\FileReference + * dimensions { + * width = 600 + * height = 400 + * } + * } + * } + * } + * 2 { + * columns { + * 1 { + * media = TYPO3\CMS\Core\Resource\FileReference + * dimensions { + * width = 600 + * height = 400 + * } + * } + * } + * } + * } + * columnSpacing = 0 + * border { + * enabled = FALSE + * width = 0 + * padding = 0 + * } + * } + * + */ +class GalleryProcessor implements DataProcessorInterface { + + /** + * The content object renderer + * + * @var \TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer + */ + protected $contentObjectRenderer; + + /** + * The processor configuration + * + * @var array + */ + protected $processorConfiguration; + + /** + * Matching the tt_content field towards the imageOrient option + * + * @var array + */ + protected $availableGalleryPositions = [ + 'horizontal' => [ + 'center' => [0, 8], + 'right' => [1, 9, 17, 25], + 'left' => [2, 10, 18, 26] + ], + 'vertical' => [ + 'above' => [0, 1, 2], + 'intext' => [17, 18, 25, 26], + 'below' => [8, 9, 10] + ] + ]; + + /** + * Storage for processed data + * + * @var array + */ + protected $galleryData = [ + 'position' => [ + 'horizontal' => '', + 'vertical' => '', + 'noWrap' => FALSE + ], + 'width' => 0, + 'count' => [ + 'files' => 0, + 'columns' => 0, + 'rows' => 0, + ], + 'columnSpacing' => 0, + 'border' => [ + 'enabled' => FALSE, + 'width' => 0, + 'padding' => 0, + ], + 'rows' => [] + ]; + + /** + * @var int + */ + protected $numberOfColumns; + + /** + * @var int + */ + protected $mediaOrientation; + + /** + * @var int + */ + protected $maxGalleryWidth; + + /** + * @var int + */ + protected $maxGalleryWidthInText; + + /** + * @var int + */ + protected $equalMediaHeight; + + /** + * @var int + */ + protected $equalMediaWidth; + + /** + * @var int + */ + protected $columnSpacing; + + /** + * @var bool + */ + protected $borderEnabled; + + /** + * @var int + */ + protected $borderWidth; + + /** + * @var int + */ + protected $borderPadding; + + /** + * The (filtered) media files to be used in the gallery + * + * @var fileObjects[] + */ + protected $fileObjects = []; + + /** + * The calculated dimensions for each media element + * + * @var array + */ + protected $mediaDimensions = []; + + /** + * Process data for a gallery, for instance the CType "textmedia" + * + * @param ContentObjectRenderer $cObj The content object renderer, which contains data of the content element + * @param array $contentObjectConfiguration The configuration of Content Object + * @param array $processorConfiguration The configuration of this processor + * @param array $processedData Key/value store of processed data (e.g. to be passed to a Fluid View) + * @return array the processed data as key/value store + * @throws ContentRenderingException + */ + public function process( + ContentObjectRenderer $cObj, + array $contentObjectConfiguration, + array $processorConfiguration, + array $processedData + ) { + if (isset($processorConfiguration['if.']) && !$cObj->checkIf($processorConfiguration['if.'])) { + return $processedData; + } + + $this->contentObjectRenderer = $cObj; + $this->processorConfiguration = $processorConfiguration; + + $filesProcessedDataKey = (string)$cObj->stdWrapValue( + 'filesProcessedDataKey', + $processorConfiguration, + 'files' + ); + if (isset($processedData[$filesProcessedDataKey]) && is_array($processedData[$filesProcessedDataKey])) { + $this->fileObjects = $processedData[$filesProcessedDataKey]; + $this->galleryData['count']['files'] = count($this->fileObjects); + } else { + throw new ContentRenderingException('No files found for key ' . $filesProcessedDataKey . ' in $processedData.', 1436809789); + } + + $this->numberOfColumns = (int)$this->getConfigurationValue('numberOfColumns', 'imagecols'); + $this->mediaOrientation = (int)$this->getConfigurationValue('mediaOrientation', 'imageorient'); + $this->maxGalleryWidth = (int)$this->getConfigurationValue('maxGalleryWidth') ?: 600; + $this->maxGalleryWidthInText = (int)$this->getConfigurationValue('maxGalleryWidthInText') ?: 300; + $this->equalMediaHeight = (int)$this->getConfigurationValue('equalMediaHeight', 'imageheight'); + $this->equalMediaWidth = (int)$this->getConfigurationValue('equalMediaWidth', 'imagewidth'); + $this->columnSpacing = (int)$this->getConfigurationValue('columnSpacing'); + $this->borderEnabled = (bool)$this->getConfigurationValue('borderEnabled', 'imageborder'); + $this->borderWidth = (int)$this->getConfigurationValue('borderWidth'); + $this->borderPadding = (int)$this->getConfigurationValue('borderPadding'); + + $this->determineGalleryPosition(); + $this->determineMaximumGalleryWidth(); + + $this->calculateRowsAndColumns(); + $this->calculateMediaWidthsAndHeights(); + + $this->prepareGalleryData(); + + $targetFieldName = (string)$cObj->stdWrapValue( + 'as', + $processorConfiguration, + 'gallery' + ); + + $processedData[$targetFieldName] = $this->galleryData; + + return $processedData; + } + + /** + * Get configuration value from processorConfiguration + * with when $dataArrayKey fallback to value from cObj->data array + * + * @param string $key + * @param string|NULL $dataArrayKey + * @return string + */ + protected function getConfigurationValue($key, $dataArrayKey = NULL) { + $defaultValue = ''; + if ($dataArrayKey && isset($this->contentObjectRenderer->data[$dataArrayKey])) { + $defaultValue = $this->contentObjectRenderer->data[$dataArrayKey]; + } + return $this->contentObjectRenderer->stdWrapValue( + $key, + $this->processorConfiguration, + $defaultValue + ); + } + + /** + * Define the gallery position + * + * Gallery has a horizontal and a vertical position towards the text + * and a possible wrapping of the text around the gallery. + * + * @return void + */ + protected function determineGalleryPosition() { + foreach ($this->availableGalleryPositions as $positionDirectionKey => $positionDirectionValue) { + foreach ($positionDirectionValue as $positionKey => $positionArray) { + if (in_array($this->mediaOrientation, $positionArray, TRUE)) { + $this->galleryData['position'][$positionDirectionKey] = $positionKey; + } + } + } + + if ($this->mediaOrientation === 25 || $this->mediaOrientation === 26) { + $this->galleryData['position']['noWrap'] = TRUE; + } + } + + /** + * Get the gallery width based on vertical position + * + * @return void + */ + protected function determineMaximumGalleryWidth() { + if ($this->galleryData['position']['vertical'] === 'intext') { + $this->galleryData['width'] = $this->maxGalleryWidthInText; + } else { + $this->galleryData['width'] = $this->maxGalleryWidth; + } + } + + /** + * Calculate the amount of rows and columns + * + * @return void + */ + protected function calculateRowsAndColumns() { + + // If no columns defined, set it to 1 + $columns = max((int)$this->numberOfColumns, 1); + + // When more columns than media elements, set the columns to the amount of media elements + if ($columns > $this->galleryData['count']['files']) { + $columns = $this->galleryData['count']['files']; + } + + if ($columns === 0) { + $columns = 1; + } + + // Calculate the rows from the amount of files and the columns + $rows = ceil($this->galleryData['count']['files'] / $columns); + + $this->galleryData['count']['columns'] = $columns; + $this->galleryData['count']['rows'] = (int)$rows; + } + + /** + * Calculate the width/height of the media elements + * + * Based on the width of the gallery, defined equal width or height by a user, the spacing between columns and + * the use of a border, defined by user, where the border width and padding are taken into account + * + * File objects MUST already be filtered. They need a height and width to be shown in the gallery + * + * @return void + */ + protected function calculateMediaWidthsAndHeights() { + + $columnSpacingTotal = ($this->galleryData['count']['columns'] - 1) * $this->columnSpacing; + + $galleryWidthMinusBorderAndSpacing = max($this->galleryData['width'] - $columnSpacingTotal, 1); + + if ($this->borderEnabled) { + $borderPaddingTotal = ($this->galleryData['count']['columns'] * 2) * $this->borderPadding; + $borderWidthTotal = ($this->galleryData['count']['columns'] * 2) * $this->borderWidth; + $galleryWidthMinusBorderAndSpacing = $galleryWidthMinusBorderAndSpacing - $borderPaddingTotal - $borderWidthTotal; + } + + // User entered a predefined height + if ($this->equalMediaHeight) { + $mediaScalingCorrection = 1; + $maximumRowWidth = 0; + + // Calculate the scaling correction when the total of media elements is wider than the gallery width + for ($row = 1; $row <= $this->galleryData['count']['rows']; $row++) { + $totalRowWidth = 0; + for ($column = 1; $column <= $this->galleryData['count']['columns']; $column++) { + $fileKey = (($row - 1) * $this->galleryData['count']['columns']) + $column - 1; + if ($fileKey > $this->galleryData['count']['files'] - 1) { + break 2; + } + $currentMediaScaling = $this->equalMediaHeight / max($this->fileObjects[$fileKey]->getProperty('height'), 1); + $totalRowWidth += $this->fileObjects[$fileKey]->getProperty('width') * $currentMediaScaling; + } + $maximumRowWidth = max($totalRowWidth, $maximumRowWidth); + $mediaInRowScaling = $totalRowWidth / $galleryWidthMinusBorderAndSpacing; + $mediaScalingCorrection = max($mediaInRowScaling, $mediaScalingCorrection); + } + + // Set the corrected dimensions for each media element + foreach ($this->fileObjects as $key => $fileObject) { + $mediaHeight = floor($this->equalMediaHeight / $mediaScalingCorrection); + $mediaWidth = floor( + $fileObject->getProperty('width') * ($mediaHeight / max($fileObject->getProperty('height'), 1)) + ); + $this->mediaDimensions[$key] = [ + 'width' => $mediaWidth, + 'height' => $mediaHeight + ]; + } + + // Recalculate gallery width + $this->galleryData['width'] = floor($maximumRowWidth / $mediaScalingCorrection); + + // User entered a predefined width + } elseif ($this->equalMediaWidth) { + $mediaScalingCorrection = 1; + + // Calculate the scaling correction when the total of media elements is wider than the gallery width + $totalRowWidth = $this->galleryData['count']['columns'] * $this->equalMediaWidth; + $mediaInRowScaling = $totalRowWidth / $galleryWidthMinusBorderAndSpacing; + $mediaScalingCorrection = max($mediaInRowScaling, $mediaScalingCorrection); + + // Set the corrected dimensions for each media element + foreach ($this->fileObjects as $key => $fileObject) { + $mediaWidth = floor($this->equalMediaWidth / $mediaScalingCorrection); + $mediaHeight = floor( + $fileObject->getProperty('height') * ($mediaWidth / max($fileObject->getProperty('width'), 1)) + ); + $this->mediaDimensions[$key] = [ + 'width' => $mediaWidth, + 'height' => $mediaHeight + ]; + } + + // Recalculate gallery width + $this->galleryData['width'] = floor($totalRowWidth / $mediaScalingCorrection); + + // Automatic setting of width and height + } else { + $maxMediaWidth = (int)($galleryWidthMinusBorderAndSpacing / $this->galleryData['count']['columns']); + + foreach ($this->fileObjects as $key => $fileObject) { + $mediaWidth = min($maxMediaWidth, $fileObject->getProperty('width')); + $mediaHeight = floor( + $fileObject->getProperty('height') * ($mediaWidth / max($fileObject->getProperty('width'), 1)) + ); + $this->mediaDimensions[$key] = [ + 'width' => $mediaWidth, + 'height' => $mediaHeight + ]; + } + } + } + + /** + * Prepare the gallery data + * + * Make an array for rows, columns and configuration + * + * @return void + */ + protected function prepareGalleryData() { + for ($row = 1; $row <= $this->galleryData['count']['rows']; $row++) { + + for ($column = 1; $column <= $this->galleryData['count']['columns']; $column++) { + + $fileKey = (($row - 1) * $this->galleryData['count']['columns']) + $column - 1; + + $this->galleryData['rows'][$row]['columns'][$column] = [ + 'media' => $this->fileObjects[$fileKey], + 'dimensions' => [ + 'width' => $this->mediaDimensions[$fileKey]['width'], + 'height' => $this->mediaDimensions[$fileKey]['height'] + ] + ]; + } + } + + $this->galleryData['columnSpacing'] = $this->columnSpacing; + $this->galleryData['border']['enabled'] = $this->borderEnabled; + $this->galleryData['border']['width'] = $this->borderWidth; + $this->galleryData['border']['padding'] = $this->borderPadding; + } +} diff --git a/typo3/sysext/frontend/Tests/Unit/Processor/GalleryProcessorTest.php b/typo3/sysext/frontend/Tests/Unit/Processor/GalleryProcessorTest.php new file mode 100644 index 000000000000..8d0184b818e9 --- /dev/null +++ b/typo3/sysext/frontend/Tests/Unit/Processor/GalleryProcessorTest.php @@ -0,0 +1,460 @@ +<?php +namespace TYPO3\CMS\Frontend\Tests\Unit\Processor; + +/* + * This file is part of the TYPO3 CMS project. + * + * It is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License, either version 2 + * of the License, or any later version. + * + * For the full copyright and license information, please read the + * LICENSE.txt file that was distributed with this source code. + * + * The TYPO3 project - inspiring people to share! + */ +use TYPO3\CMS\Core\Resource\FileReference; +use TYPO3\CMS\Core\Tests\UnitTestCase; +use TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer; +use TYPO3\CMS\Frontend\DataProcessing\GalleryProcessor; + +/** + * Tests for GalleryProcessor + */ +class GalleryProcessorTest extends UnitTestCase { + + /** + * @var ContentObjectRenderer|\PHPUnit_Framework_MockObject_MockObject + */ + protected $contentObjectRenderer; + + /** + * Set up + */ + protected function setUp() { + $this->contentObjectRenderer = $this->getMock( + ContentObjectRenderer::class, + ['dummy'] + ); + } + + /** + * @test + * @expectedException \TYPO3\CMS\Frontend\ContentObject\Exception\ContentRenderingException + */ + public function processThrowsExceptionWhenFilesProcessedDataKeyIsNotFound() { + $processor = new GalleryProcessor(); + $processor->process( + $this->contentObjectRenderer, + [], + [], + [] + ); + } + + /** + * Gallery position test data provider + */ + public function galleryPositionDataProvider() { + return [ + 'Default: horizontal above' => [ + [], + [ + 'horizontal' => 'center', + 'vertical' => 'above', + 'noWrap' => FALSE + ] + ], + 'right above' => [ + ['mediaOrientation' => 1], + [ + 'horizontal' => 'right', + 'vertical' => 'above', + 'noWrap' => FALSE + ] + ], + 'left above' => [ + ['mediaOrientation' => 2], + [ + 'horizontal' => 'left', + 'vertical' => 'above', + 'noWrap' => FALSE + ] + ], + 'center below' => [ + ['mediaOrientation' => 8], + [ + 'horizontal' => 'center', + 'vertical' => 'below', + 'noWrap' => FALSE + ] + ], + 'right below' => [ + ['mediaOrientation' => 9], + [ + 'horizontal' => 'right', + 'vertical' => 'below', + 'noWrap' => FALSE + ] + ], + 'left below' => [ + ['mediaOrientation' => 10], + [ + 'horizontal' => 'left', + 'vertical' => 'below', + 'noWrap' => FALSE + ] + ], + 'right intext' => [ + ['mediaOrientation' => 17], + [ + 'horizontal' => 'right', + 'vertical' => 'intext', + 'noWrap' => FALSE + ] + ], + 'left intext' => [ + ['mediaOrientation' => 18], + [ + 'horizontal' => 'left', + 'vertical' => 'intext', + 'noWrap' => FALSE + ] + ], + 'right intext no wrap' => [ + ['mediaOrientation' => 25], + [ + 'horizontal' => 'right', + 'vertical' => 'intext', + 'noWrap' => TRUE + ] + ], + 'left intext no wrap' => [ + ['mediaOrientation' => 26], + [ + 'horizontal' => 'left', + 'vertical' => 'intext', + 'noWrap' => TRUE + ] + ], + + ]; + } + + /** + * @test + * @dataProvider galleryPositionDataProvider + */ + public function galleryPositionTest($processorConfiguration, $expected) { + $processor = new GalleryProcessor(); + $processedData = $processor->process( + $this->contentObjectRenderer, + [], + $processorConfiguration, + ['files' => []] + ); + + $this->assertEquals($expected, $processedData['gallery']['position']); + } + + /** + * @test + */ + public function maxGalleryWidthTest() { + $processor = new GalleryProcessor(); + $processedData = $processor->process( + $this->contentObjectRenderer, + [], + ['maxGalleryWidth' => 200, 'maxGalleryWidthInText' => 100], + ['files' => []] + ); + + $this->assertEquals(200, $processedData['gallery']['width']); + } + + /** + * @test + */ + public function maxGalleryWidthWhenInTextTest() { + $processor = new GalleryProcessor(); + $processedData = $processor->process( + $this->contentObjectRenderer, + [], + ['maxGalleryWidth' => 200, 'maxGalleryWidthInText' => 100, 'mediaOrientation' => 26], + ['files' => []] + ); + + $this->assertEquals(100, $processedData['gallery']['width']); + } + + /** + * Count test data provider + * @return array + */ + public function countDataProvider() { + return [ + 'Default settings with 3 files' => [ + 3, + [], + [], + [ + 'files' => 3, + 'columns' => 1, + 'rows' => 3 + ] + ], + 'NumberOfColumns set by value' => [ + 3, + [], + ['numberOfColumns' => 2], + [ + 'files' => 3, + 'columns' => 2, + 'rows' => 2 + ] + ], + 'NumberOfColumns set in data' => [ + 3, + ['imagecols' => 3], + [], + [ + 'files' => 3, + 'columns' => 3, + 'rows' => 1 + ] + ], + 'NumberOfColumns set in custom data field' => [ + 6, + ['my_imagecols' => 4], + ['numberOfColumns.' => [ + 'field' => 'my_imagecols' + ]], + [ + 'files' => 6, + 'columns' => 4, + 'rows' => 2 + ] + ] + ]; + } + + /** + * @test + * @dataProvider countDataProvider + */ + public function countResultTest($numberOfFiles, $data, $processorConfiguration, $expected) { + $files = []; + for ($i = 0; $i < $numberOfFiles; $i++) { + $files[] = $this->getMock(FileReference::class, array(), array(), '', FALSE); + } + $this->contentObjectRenderer->data = $data; + $processor = new GalleryProcessor(); + $processedData = $processor->process( + $this->contentObjectRenderer, + [], + $processorConfiguration, + ['files' => $files] + ); + + $this->assertEquals($expected, $processedData['gallery']['count']); + } + + /** + * Data provider for calculateMediaWidthsAndHeightsTest + * + * @return array + */ + public function calculateMediaWidthsAndHeightsDataProvider() { + return [ + 'Default settings' => [ + [ + [200, 100], + [200, 100], + [200, 100], + ], + [], + [ + 1 => [ + 1 => ['width' => 200, 'height' => 100] + ], + 2 => [ + 1 => ['width' => 200, 'height' => 100] + ], + 3 => [ + 1 => ['width' => 200, 'height' => 100] + ], + ] + ], + 'Max width set + number of columns set' => [ + [ + [200, 100], + [200, 100], + [200, 100], + ], + ['maxGalleryWidth' => 200, 'numberOfColumns' => 2], + [ + 1 => [ + 1 => ['width' => 100, 'height' => 50], + 2 => ['width' => 100, 'height' => 50] + ], + 2 => [ + 1 => ['width' => 100, 'height' => 50], + 2 => ['width' => NULL, 'height' => NULL] + ], + ] + ], + 'Max width set, number of columns + border (padding) set' => [ + [ + [200, 100], + [200, 100], + [200, 100], + ], + [ + 'maxGalleryWidth' => 200, + 'numberOfColumns' => 2, + 'borderEnabled' => TRUE, + 'borderPadding' => 4, + 'borderWidth' => 0, + ], + [ + 1 => [ + 1 => ['width' => 92, 'height' => 46], + 2 => ['width' => 92, 'height' => 46] + ], + 2 => [ + 1 => ['width' => 92, 'height' => 46], + 2 => ['width' => NULL, 'height' => NULL] + ], + ] + ], + 'Max width set, number of columns + border (width) set' => [ + [ + [200, 100], + [200, 100], + [200, 100], + ], + [ + 'maxGalleryWidth' => 200, + 'numberOfColumns' => 2, + 'borderEnabled' => TRUE, + 'borderPadding' => 0, + 'borderWidth' => 4, + ], + [ + 1 => [ + 1 => ['width' => 92, 'height' => 46], + 2 => ['width' => 92, 'height' => 46] + ], + 2 => [ + 1 => ['width' => 92, 'height' => 46], + 2 => ['width' => NULL, 'height' => NULL] + ], + ] + ], + 'Max width set, number of columns + border (padding + width) set' => [ + [ + [200, 100], + [200, 100], + [200, 100], + ], + [ + 'maxGalleryWidth' => 200, + 'numberOfColumns' => 2, + 'borderEnabled' => TRUE, + 'borderPadding' => 1, + 'borderWidth' => 4, + ], + [ + 1 => [ + 1 => ['width' => 90, 'height' => 45], + 2 => ['width' => 90, 'height' => 45] + ], + 2 => [ + 1 => ['width' => 90, 'height' => 45], + 2 => ['width' => NULL, 'height' => NULL] + ], + ] + ], + 'Equal height set' => [ + [ + [200, 100], + [200, 300], + [100, 50], + [2020, 1000], + [1000, 1000], + ], + [ + 'maxGalleryWidth' => 500, + 'numberOfColumns' => 3, + 'equalMediaHeight' => 75 + ], + [ + 1 => [ + 1 => ['width' => 150, 'height' => 75], + 2 => ['width' => 50, 'height' => 75], + 3 => ['width' => 150, 'height' => 75] + ], + 2 => [ + 1 => ['width' => 151, 'height' => 75], + 2 => ['width' => 75, 'height' => 75], + 3 => ['width' => NULL, 'height' => NULL] + ], + ] + ], + 'Equal width set' => [ + [ + [200, 100], + [200, 300], + [100, 50], + ], + [ + 'maxGalleryWidth' => 200, + 'numberOfColumns' => 3, + 'equalMediaWidth' => 75 + ], + [ + 1 => [ + 1 => ['width' => 66, 'height' => 33], + 2 => ['width' => 66, 'height' => 99], + 3 => ['width' => 66, 'height' => 33] + ], + ] + ] + ]; + } + + /** + * @test + * @dataProvider calculateMediaWidthsAndHeightsDataProvider + */ + public function calculateMediaWidthsAndHeightsTest($testFiles, $processorConfiguration, $expected) { + $files = []; + foreach ($testFiles as $fileConfig) { + $fileReference = $this->getMock(FileReference::class, array(), array(), '', FALSE); + $fileReference->expects($this->any()) + ->method('getProperty') + ->will($this->returnValueMap([ + ['width', $fileConfig[0]], + ['height', $fileConfig[1]] + ])); + $files[] = $fileReference; + } + + $processor = new GalleryProcessor(); + $processedData = $processor->process( + $this->contentObjectRenderer, + [], + $processorConfiguration, + ['files' => $files] + ); + + foreach ($expected as $row => $columns) { + $this->assertArrayHasKey($row, $processedData['gallery']['rows'], 'Row exists'); + foreach ($columns as $column => $dimensions) { + $this->assertArrayHasKey($column, $processedData['gallery']['rows'][$row]['columns'], 'Column exists'); + $this->assertEquals($dimensions, $processedData['gallery']['rows'][$row]['columns'][$column]['dimensions'], 'Dimensions match'); + } + } + } + +} \ No newline at end of file -- GitLab