diff --git a/.gitignore b/.gitignore index 0d31019..59248e5 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ .sass-cache/ +vendor/ diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..2b0a6d6 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,33 @@ +language: php + +git: + depth: 1 + +cache: + directories: + - $HOME/.composer/cache + +sudo: false + +env: + global: + - COMPOSER_ALLOW_XDEBUG=0 + - SYMFONY_DEPRECATIONS_HELPER=weak + +matrix: + include: + - php: 5.6 + - php: 7.0 + - php: 7.0 + env: COMPOSER_FLAGS='--prefer-lowest --prefer-stable' + - php: 7.1 + fast_finish: true + +before_install: + - composer selfupdate + +before_script: + - travis_wait composer update $COMPOSER_FLAGS --no-interaction + +script: + - php vendor/bin/phpunit diff --git a/composer.json b/composer.json index 587dc3b..de98bbf 100644 --- a/composer.json +++ b/composer.json @@ -18,11 +18,18 @@ "source":"https://github.com/madeyourday/contao-rocksolid-slider" }, "require":{ - "php":">=5.5", + "php":">=5.6", "contao/core-bundle":"^4.3" }, "require-dev": { - "contao/manager-plugin": "^2.0" + "contao/news-bundle":"^4.3", + "contao/calendar-bundle": "^4.3", + "contao/manager-plugin": "^2.0", + "phpunit/phpunit": "^5.7 | ^6.1" + }, + "suggest": { + "contao/news-bundle": "To create sliders from news entries (requires license key).", + "contao/calendar-bundle": "To create sliders from calendar events (requires license key)." }, "conflict": { "contao/core": "*", @@ -33,6 +40,11 @@ "MadeYourDay\\RockSolidSlider\\": "src/" } }, + "autoload-dev":{ + "psr-4": { + "MadeYourDay\\RockSolidSlider\\Test\\": "tests/" + } + }, "extra": { "contao-manager-plugin": "MadeYourDay\\RockSolidSlider\\ContaoManagerPlugin" }, diff --git a/phpunit.xml.dist b/phpunit.xml.dist new file mode 100644 index 0000000..528677b --- /dev/null +++ b/phpunit.xml.dist @@ -0,0 +1,31 @@ + + + + + + + + + ./tests + ./tests/Fixtures + + + + + + src + + ./src/Resources + + + + diff --git a/src/DependencyInjection/Compiler/AddProvidersPass.php b/src/DependencyInjection/Compiler/AddProvidersPass.php new file mode 100644 index 0000000..8f9ca0f --- /dev/null +++ b/src/DependencyInjection/Compiler/AddProvidersPass.php @@ -0,0 +1,52 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace MadeYourDay\RockSolidSlider\DependencyInjection\Compiler; + +use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface; +use Symfony\Component\DependencyInjection\ContainerBuilder; +use Symfony\Component\DependencyInjection\Reference; + +/** + * Adds the providers to the registry. + * + * @author Christian Schiffler + */ +class AddProvidersPass implements CompilerPassInterface +{ + /** + * {@inheritdoc} + */ + public function process(ContainerBuilder $container) + { + $definition = $container->getDefinition('madeyourday.rocksolid_slider.slideproviders'); + $arguments = $definition->getArguments(); + + // Collect provider services. + $arguments[0] = array_merge(count($arguments) > 0 ? $arguments[0] : [], $this->getProviders($container)); + + $definition->setArguments($arguments); + } + + /** + * Returns the available provider implementations. + * + * @return Reference[] + */ + private function getProviders(ContainerBuilder $container) + { + $services = $container->findTaggedServiceIds('madeyourday.rocksolid_slider.slideprovider'); + $result = []; + foreach (array_keys($services) as $service) { + $result[] = new Reference($service); + } + + return $result; + } +} diff --git a/src/DependencyInjection/RockSolidSliderExtension.php b/src/DependencyInjection/RockSolidSliderExtension.php new file mode 100644 index 0000000..4e5d4ba --- /dev/null +++ b/src/DependencyInjection/RockSolidSliderExtension.php @@ -0,0 +1,30 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace MadeYourDay\RockSolidSlider\DependencyInjection; + +use Symfony\Component\Config\FileLocator; +use Symfony\Component\DependencyInjection\ContainerBuilder; +use Symfony\Component\DependencyInjection\Extension\Extension; +use Symfony\Component\DependencyInjection\Loader; + +/** + * This is the class that loads and manages the bundle configuration + */ +class RockSolidSliderExtension extends Extension +{ + /** + * {@inheritDoc} + */ + public function load(array $configs, ContainerBuilder $container) + { + $loader = new Loader\YamlFileLoader($container, new FileLocator(__DIR__ . '/../Resources/config')); + $loader->load('services.yml'); + } +} diff --git a/src/Helper/FileHelper.php b/src/Helper/FileHelper.php new file mode 100644 index 0000000..e6e5ba7 --- /dev/null +++ b/src/Helper/FileHelper.php @@ -0,0 +1,239 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace MadeYourDay\RockSolidSlider\Helper; + +use Contao\CoreBundle\Framework\Adapter; +use Contao\File; +use Contao\FilesModel; +use Contao\Frontend; +use Contao\Model\Collection; +use Contao\StringUtil; +use Contao\Validator; + +/** + * This class is a helper service for processing files. + * + * @author Christian Schiffler + */ +class FileHelper +{ + /** + * @var Adapter|FilesModel + */ + private $filesModelAdapter; + + /** + * @var Adapter|Frontend + */ + private $frontendAdapter; + + /** + * Create a new instance. + * + * @param Adapter|FilesModel $filesModelAdapter + * @param Adapter|Frontend $frontendAdapter + */ + public function __construct(Adapter $filesModelAdapter, Adapter $frontendAdapter) + { + $this->filesModelAdapter = $filesModelAdapter; + $this->frontendAdapter = $frontendAdapter; + } + + /** + * Find multiple files by their UUIDs. + * + * @param array $uuids An array of UUIDs. + * @param array $options An optional options array. + * + * @return Collection|FilesModel[]|FilesModel|null A collection of models or null if there are no files. + */ + public function findMultipleFilesByUuids($uuids, array $options = []) + { + return $this->filesModelAdapter->findMultipleByUuids($uuids, $options); + } + + /** + * Find multiple files by their UUIDs. + * + * @param string[]|Collection|FilesModel[] $uuids An array of UUIDs to be used as pid. + * @param array $options An optional options array. + * + * @return Collection|FilesModel[]|FilesModel|null A collection of models or null if there are no files. + */ + public function findMultipleFilesByUuidRecursive($uuids, array $options = []) + { + $result = []; + $dirs = []; + if (!$uuids instanceof Collection) { + $uuids = $this->findMultipleFilesByUuids($uuids, $options); + } + + foreach ($uuids as $file) { + if ($file->type === 'file') { + $result[] = $file; + continue; + } + + $dirs[] = $file->uuid; + } + if (empty($dirs)) { + return $result; + } + + return array_merge($result, $this->findMultipleFilesByPidRecursive($dirs, $options)); + } + + /** + * Find multiple files by their UUID-pid. + * + * @param string[]|Collection|FilesModel[] $pids An array of UUIDs to be used as pid. + * @param array $options An optional options array. + * + * @return Collection|FilesModel[]|FilesModel|null A collection of models or null if there are no files. + */ + public function findMultipleFilesByPidRecursive($pids, array $options = []) + { + $result = []; + $dirs = []; + if (!$pids instanceof Collection) { + $pids = $this->filesModelAdapter->findBy([ + $this->filesModelAdapter->getTable() . '.pid IN (' . + implode(',', array_fill(0, count($pids), 'UNHEX(?)')) . ')' + ], array_map(function ($id) { + return Validator::isStringUuid($id) ? bin2hex(StringUtil::uuidToBin($id)) : bin2hex($id); + }, $pids), $options); + } + + foreach ($pids as $file) { + if ($file->type === 'file') { + $result[] = $file; + continue; + } + + $dirs[] = $file->uuid; + } + + if (empty($dirs)) { + return $result; + } + + return array_merge($result, $this->findMultipleFilesByPidRecursive($dirs, $options)); + } + + /** + * Gateway to frontend adapter. + * + * @param array $data The image data as array. + * + * @return \stdClass + */ + public function prepareImageForTemplate($data) + { + $image = new \stdClass; + $this->frontendAdapter->addImageToTemplate($image, $data); + + return $image; + } + + /** + * Try to prepare the file with the passed uuid. + * + * @param string|FilesModel $uuidOrModel The uuid of the file. + * @param array $attributes The attributes to pass to Frontend::addImageToTemplate(). + * @param bool $addMeta If true, the Meta information attributes will also get added + * 'alt' => meta['title'] + * 'imageUrl' => meta['link'], + * 'caption' => meta['caption'] + * + * @return null|array + */ + public function tryPrepareImage($uuidOrModel, $attributes, $addMeta = false) + { + if (null === ($file = $this->ensureFileModel($uuidOrModel))) { + return null; + } + $fileObject = $this->getFileInstance($file->path); + // FIXME: Why check for isGdImage here? if isImage == true it is always also isGdImage == true? + if (!$fileObject->isGdImage && !$fileObject->isImage) { + return null; + } + + if ($addMeta) { + // FIXME: this is only needed because of the language, we need it via another way! + global $objPage; + $meta = $this->frontendAdapter->getMetaData($file->meta, $objPage->language); + $attributes['alt'] = $meta['title']; + $attributes['imageUrl'] = $meta['link']; + $attributes['caption'] = $meta['caption']; + } + + return array_merge([ + 'id' => $file->id, + 'uuid' => isset($file->uuid) ? $file->uuid : null, + 'name' => $fileObject->basename, + 'singleSRC' => $file->path, + ], $attributes); + } + + /** + * Try to prepare the file with the passed uuid. + * + * @param string|FilesModel $uuidOrModel The uuid of the file. + * @param array $attributes The attributes to pass to Frontend::addImageToTemplate(). + * @param bool $addMeta If true, the Meta information attributes will also get added + * 'alt' => meta['title'] + * 'imageUrl' => meta['link'], + * 'caption' => meta['caption'] + * + * @return null|\stdClass + */ + public function tryPrepareImageForTemplate($uuidOrModel, $attributes, $addMeta = false) + { + if (null === ($imageData = $this->tryPrepareImage($uuidOrModel, $attributes, $addMeta))) { + return null; + } + + return $this->prepareImageForTemplate($imageData); + } + + /** + * Instantiate a file instance and return it. + * + * The purpose of this function is to be able to mock it in tests and to replace it when needed. + * + * @param string $path The path below TL_ROOT. + * + * @return File + */ + public function getFileInstance($path) + { + return new File($path); + } + + /** + * Convert an uuid to a FilesModel instance if not one already. + * + * @param string|FilesModel $uuidOrModel + * + * @return FilesModel|null + */ + private function ensureFileModel($uuidOrModel) + { + if ($uuidOrModel instanceof FilesModel) { + return $uuidOrModel; + } + + if (!trim($uuidOrModel)) { + return null; + } + + return $this->filesModelAdapter->findByUuid($uuidOrModel); + } +} diff --git a/src/Module/Slider.php b/src/Module/Slider.php index 385e72f..a70e131 100644 --- a/src/Module/Slider.php +++ b/src/Module/Slider.php @@ -8,14 +8,22 @@ namespace MadeYourDay\RockSolidSlider\Module; -use MadeYourDay\RockSolidSlider\Model\SlideModel; +use Contao\System; +use MadeYourDay\RockSolidSlider\Helper\FileHelper; use MadeYourDay\RockSolidSlider\Model\SliderModel; -use MadeYourDay\RockSolidSlider\Model\ContentModel; +use MadeYourDay\RockSolidSlider\SliderContent; /** * Slider Frontend Module * * @author Martin Auswöger + * + * @property string rsts_content_type The slider content type. + * @property string rsts_thumbs_imgSize + * @property string rsts_navType + * @property string rsts_template + * @property string rsts_import_settings + * @property string rsts_import_settings_from */ class Slider extends \Module { @@ -24,6 +32,16 @@ class Slider extends \Module */ protected $strTemplate = 'rsts_default'; + /** + * @var SliderContent + */ + private $content; + + /** + * @var string + */ + private $root; + /** * @return string */ @@ -48,52 +66,19 @@ public function generate() return $template->parse(); } - if ($this->rsts_content_type === 'rsts_news') { - $newsModule = new SliderNews($this->objModel, $this->strColumn); - $this->newsArticles = $newsModule->getNewsArticles(); - if (!count($this->newsArticles)) { - // Return if there are no news articles + $registry = System::getContainer()->get('madeyourday.rocksolid_slider.slideproviders'); + /** @var \MadeYourDay\RockSolidSlider\SlideProvider\SlideProviderRegistry $registry */ + if ($registry->hasProvider($this->rsts_content_type)) { + $this->content = new SliderContent(); + $registry + ->getProvider($this->rsts_content_type) + ->process(array_merge(['slider-column' => $this->strColumn], $this->objModel->row()), $this->content); + if (!$this->content->hasSlides() && !$this->content->hasFiles()) { return ''; } } - else if ($this->rsts_content_type === 'rsts_events') { - $eventsModule = new SliderEvents($this->objModel, $this->strColumn); - $this->eventItems = $eventsModule->getEventItems(); - if (!count($this->eventItems)) { - // Return if there are no events - return ''; - } - } - else if ($this->rsts_content_type === 'rsts_settings') { - return ''; - } - else if ($this->rsts_content_type === 'rsts_images' || !$this->rsts_id) { - - $this->multiSRC = deserialize($this->multiSRC); - if (!is_array($this->multiSRC) || !count($this->multiSRC)) { - // Return if there are no images - return ''; - } - - } - else { - - $this->slider = SliderModel::findByPk($this->rsts_id); - - // Return if there is no slider - if (! $this->slider || $this->slider->id !== $this->rsts_id) { - return ''; - } - - if ($this->slider->type === 'image') { - $this->multiSRC = deserialize($this->slider->multiSRC); - $this->orderSRC = $this->slider->orderSRC; - } - - } - - $this->files = \FilesModel::findMultipleByUuids($this->multiSRC); + $this->root = dirname(System::getContainer()->getParameter('kernel.root_dir')); if ( $this->rsts_import_settings && $this->rsts_import_settings_from @@ -123,125 +108,13 @@ public function generate() */ protected function compile() { - global $objPage; - - $images = array(); - - if ($this->files) { - - $files = $this->files; - $filesExpaned = array(); - - // Get all images - while ($files->next()) { - if ($files->type === 'file') { - $filesExpaned[] = $files->current(); - } - else { - $subFiles = \FilesModel::findByPid($files->uuid); - while ($subFiles && $subFiles->next()) { - if ($subFiles->type === 'file'){ - $filesExpaned[] = $subFiles->current(); - } - } - } - } - - foreach ($filesExpaned as $files) { - - // Continue if the files has been processed or does not exist - if (isset($images[$files->path]) || ! file_exists(TL_ROOT . '/' . $files->path)) { - continue; - } - - $file = new \File($files->path, true); - - if (!$file->isGdImage && !$file->isImage) { - continue; - } - - $arrMeta = $this->getMetaData($files->meta, $objPage->language); - - // Add the image - $images[$files->path] = array - ( - 'id' => $files->id, - 'uuid' => isset($files->uuid) ? $files->uuid : null, - 'name' => $file->basename, - 'singleSRC' => $files->path, - 'alt' => $arrMeta['title'], - 'imageUrl' => $arrMeta['link'], - 'caption' => $arrMeta['caption'], - ); - - } - - if ($this->orderSRC) { - // Turn the order string into an array and remove all values - $order = deserialize($this->orderSRC); - if (!$order || !is_array($order)) { - $order = array(); - } - $order = array_flip($order); - $order = array_map(function(){}, $order); - - // Move the matching elements to their position in $order - foreach ($images as $k => $v) { - if (array_key_exists($v['uuid'], $order)) { - $order[$v['uuid']] = $v; - unset($images[$k]); - } - } - - $order = array_merge($order, array_values($images)); - - // Remove empty (unreplaced) entries - $images = array_filter($order); - unset($order); - } - - $images = array_values($images); - - foreach ($images as $key => $image) { - $newImage = new \stdClass(); - $image['size'] = isset($this->imgSize) ? $this->imgSize : $this->size; - $this->addImageToTemplate($newImage, $image); - if ($this->rsts_navType === 'thumbs') { - $newImage->thumb = new \stdClass; - $image['size'] = $this->rsts_thumbs_imgSize; - $this->addImageToTemplate($newImage->thumb, $image); - } - $images[$key] = $newImage; - } - - } - // use custom skin if specified if (trim($this->arrData['rsts_customSkin'])) { $this->arrData['rsts_skin'] = trim($this->arrData['rsts_customSkin']); } - $this->Template->images = $images; - $slides = array(); - if (isset($this->newsArticles)) { - foreach ($this->newsArticles as $newsArticle) { - $slides[] = array( - 'text' => $newsArticle, - ); - } - } - else if (isset($this->eventItems)) { - foreach ($this->eventItems as $eventItem) { - $slides[] = array( - 'text' => $eventItem, - ); - } - } - else if (isset($this->slider->id) && $this->slider->type === 'content') { - $slides = $this->parseSlides(SlideModel::findPublishedByPid($this->slider->id)); - } - - $this->Template->slides = $slides; + $this->Template->images = $this->prepareFiles($this->content->getFiles(), $this->content->getFilesOrder()); + $this->Template->slides = $this->content->getSlides(); $options = array(); @@ -385,186 +258,79 @@ protected function compile() $GLOBALS['TL_JAVASCRIPT'][] = $assetsDir . '/js/rocksolid-slider.min.js|static'; $GLOBALS['TL_CSS'][] = $assetsDir . '/css/rocksolid-slider.min.css||static'; $skinPath = $assetsDir . '/css/' . (empty($this->arrData['rsts_skin']) ? 'default' : $this->arrData['rsts_skin']) . '-skin.min.css'; - if (file_exists(TL_ROOT . '/' . $skinPath)) { + if (file_exists($this->root . '/' . $skinPath)) { $GLOBALS['TL_CSS'][] = $skinPath . '||static'; } } /** - * Parse slides + * Prepare the images. + * + * @param array $files The file list. + * @param array $order The order list. * - * @param \Model\Collection $objSlides slides retrieved from the database - * @return array parsed slides + * @return array */ - protected function parseSlides($objSlides) + private function prepareFiles($files, $order) { - global $objPage; - - $slides = array(); - $pids = array(); - $idIndexes = array(); - - if (! $objSlides) { - return $slides; + if (empty($files)) { + return []; } + /** @var FileHelper $helper */ + $helper = System::getContainer()->get('madeyourday.rocksolid_slider.file_helper'); + $images = []; + foreach ($helper->findMultipleFilesByUuidRecursive($files) as $files) { - while ($objSlides->next()) { - - $slide = $objSlides->row(); - $slide['text'] = ''; - if ($slide['type'] === 'content') { - $pids[] = $slide['id']; - $idIndexes[(int)$slide['id']] = count($slides); + // Continue if the files has been processed or does not exist + if (isset($images[$files->path]) || !file_exists($this->root . '/' . $files->path)) { + continue; } - if ( - in_array($slide['type'], array('image', 'video')) && - trim($slide['singleSRC']) && - ($file = \FilesModel::findByUuid($slide['singleSRC'])) && - ($fileObject = new \File($file->path, true)) && - ($fileObject->isGdImage || $fileObject->isImage) - ) { - $meta = $this->getMetaData($file->meta, $objPage->language); - $slide['image'] = new \stdClass; - $this->addImageToTemplate($slide['image'], array( - 'id' => $file->id, - 'name' => $fileObject->basename, - 'singleSRC' => $file->path, - 'alt' => $meta['title'], - 'imageUrl' => $meta['link'], - 'caption' => $meta['caption'], - 'size' => isset($this->imgSize) ? $this->imgSize : $this->size, - )); + if (null !== ($imageData = $helper->tryPrepareImage($files, [], true))) { + // Add the image + $images[$files->path] = $imageData; } + } - if ($slide['type'] === 'video' && $slide['videoURL'] && empty($slide['image'])) { - $slide['image'] = new \stdClass; - if (preg_match( - '(^ - https?:// # http or https - (?: - www\\.youtube\\.com/(?:watch\\?v=|v/|embed/) # Different URL formats - | youtu\\.be/ # Short YouTube domain - ) - ([0-9a-z_\\-]{11}) # YouTube ID - (?:$|&|/) # End or separator - )ix', - html_entity_decode($slide['videoURL']), $matches) - ) { - $video = $matches[1]; - $slide['image']->src = '//img.youtube.com/vi/' . $video . '/0.jpg'; + if ($order) { + // Turn the order string into an array and remove all values + if (!$order || !is_array($order)) { + $order = array(); + } + $order = array_flip($order); + $order = array_map( + function () { + }, + $order + ); + + // Move the matching elements to their position in $order + foreach ($images as $k => $v) { + if (array_key_exists($v['uuid'], $order)) { + $order[$v['uuid']] = $v; + unset($images[$k]); } - else { - // Grey dummy image - $slide['image']->src = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAJCAMAAAAM9FwAAAAAA1BMVEXGxsbd/8BlAAAAFUlEQVR42s3BAQEAAACAkP6vdiO6AgCZAAG/wrlvAAAAAElFTkSuQmCC'; - } - $slide['image']->imgSize = ''; - $slide['image']->alt = ''; - $slide['image']->picture = array( - 'img' => array('src' => $slide['image']->src, 'srcset' => $slide['image']->src), - 'sources' => array(), - ); - } - - if ($slide['type'] !== 'video' && $slide['videoURL']) { - $slide['videoURL'] = ''; } - if ($slide['type'] === 'video' && $slide['videos']) { - $videoFiles = deserialize($slide['videos'], true); - $videoFiles = \FilesModel::findMultipleByUuids($videoFiles); - $videos = array(); - foreach ($videoFiles as $file) { - $videos[] = $file; - } - $slide['videos'] = $videos; - } - else { - $slide['videos'] = null; - } + $order = array_merge($order, array_values($images)); - if ( - trim($slide['backgroundImage']) && - ($file = \FilesModel::findByUuid($slide['backgroundImage'])) && - ($fileObject = new \File($file->path, true)) && - ($fileObject->isGdImage || $fileObject->isImage) - ) { - $meta = $this->getMetaData($file->meta, $objPage->language); - $slide['backgroundImage'] = new \stdClass; - $this->addImageToTemplate($slide['backgroundImage'], array( - 'id' => $file->id, - 'name' => $fileObject->basename, - 'singleSRC' => $file->path, - 'alt' => $meta['title'], - 'imageUrl' => $meta['link'], - 'caption' => $meta['caption'], - 'size' => $slide['backgroundImageSize'], - )); - } - else { - $slide['backgroundImage'] = null; - } + // Remove empty (unreplaced) entries + $images = array_filter($order); + unset($order); + } - if ($slide['backgroundVideos']) { - $videoFiles = deserialize($slide['backgroundVideos'], true); - $videoFiles = \FilesModel::findMultipleByUuids($videoFiles); - $videos = array(); - foreach ($videoFiles as $file) { - $videos[] = $file; - } - $slide['backgroundVideos'] = $videos; - } + $images = array_values($images); + foreach ($images as $key => $image) { + $image['size'] = isset($this->imgSize) ? $this->imgSize : $this->size; + $newImage = $helper->prepareImageForTemplate($image); if ($this->rsts_navType === 'thumbs') { - $slide['thumb'] = new \stdClass; - if ( - trim($slide['thumbImage']) && - ($file = \FilesModel::findByUuid($slide['thumbImage'])) && - ($fileObject = new \File($file->path, true)) && - ($fileObject->isGdImage || $fileObject->isImage) - ) { - $this->addImageToTemplate($slide['thumb'], array( - 'id' => $file->id, - 'name' => $fileObject->basename, - 'singleSRC' => $file->path, - 'size' => $this->rsts_thumbs_imgSize, - )); - } - elseif ( - in_array($slide['type'], array('image', 'video')) && - trim($slide['singleSRC']) && - ($file = \FilesModel::findByUuid($slide['singleSRC'])) && - ($fileObject = new \File($file->path, true)) && - ($fileObject->isGdImage || $fileObject->isImage) - ) { - $this->addImageToTemplate($slide['thumb'], array( - 'id' => $file->id, - 'name' => $fileObject->basename, - 'singleSRC' => $file->path, - 'size' => $this->rsts_thumbs_imgSize, - )); - } - elseif (!empty($slide['image']->src)) { - $slide['thumb'] = clone $slide['image']; - } - elseif (!empty($slide['backgroundImage']->src)) { - $slide['thumb'] = clone $slide['backgroundImage']; - } - } - - $slides[] = $slide; - - } - - if (count($pids)) { - $slideContents = ContentModel::findPublishedByPidsAndTable($pids, SlideModel::getTable()); - if ($slideContents) { - while ($slideContents->next()) { - $slides[$idIndexes[(int)$slideContents->pid]]['text'] .= $this->getContentElement($slideContents->current()); - } + $image['size'] = $this->rsts_thumbs_imgSize; + $newImage->thumb = $helper->prepareImageForTemplate($image); } + $images[$key] = $newImage; } - return $slides; + return $images; } } diff --git a/src/Module/SliderEvents.php b/src/Module/SliderEvents.php index a32d6de..22f6d65 100644 --- a/src/Module/SliderEvents.php +++ b/src/Module/SliderEvents.php @@ -8,15 +8,15 @@ namespace MadeYourDay\RockSolidSlider\Module; +@trigger_error('Class MadeYourDay\RockSolidSlider\Module\SliderEvents is deprecated and will get removed.', E_USER_DEPRECATED); + /** * Slider Events Module * * @author Martin Auswöger */ -class SliderEvents extends \ModuleEventlist +class SliderEvents extends \MadeYourDay\RockSolidSlider\SlideProvider\Bridge\ContaoEvents { - const TEMPLATE_SEPARATOR = ''; - /** * Get an array of events (HTML output) generated by Contao\ModuleEventlist * @@ -24,45 +24,11 @@ class SliderEvents extends \ModuleEventlist */ public function getEventItems() { - $this->cal_calendar = $this->sortOutProtected(deserialize($this->cal_calendar, true)); - - // Return if there are no calendars - if (!is_array($this->cal_calendar) || empty($this->cal_calendar)) - { - return array(); + $slides = parent::getSlides(); + $articles = []; + foreach ($slides as $slide) { + $articles[] = $slide['text']; } - - // Dummy template object to retrive data from the compile method - $this->Template = new \stdClass; - $this->perPage = 0; - - $parseTemplateHook = array( - 'MadeYourDay\\RockSolidSlider\\Slider', - 'parseEventsTemplateHook' - ); - // Add the TEMPLATE_SEPARATOR to be able to split the output into single events - $GLOBALS['TL_HOOKS']['parseFrontendTemplate'][] = $parseTemplateHook; - - $this->compile(); - - // Remove the hook - foreach ($GLOBALS['TL_HOOKS']['parseFrontendTemplate'] as $key => $hook) { - if ($hook[0] === $parseTemplateHook[0] && $hook[1] === $parseTemplateHook[1]) { - unset($GLOBALS['TL_HOOKS']['parseFrontendTemplate'][$key]); - } - } - - // Split the output into single event items - $eventItems = explode(static::TEMPLATE_SEPARATOR, $this->Template->events); - - if (count($eventItems) < 2) { - // No events found - return array(); - } - - // Remove output before the first event - array_shift($eventItems); - - return $eventItems; + return $articles; } } diff --git a/src/Module/SliderNews.php b/src/Module/SliderNews.php index f8d55a7..f93ddf2 100644 --- a/src/Module/SliderNews.php +++ b/src/Module/SliderNews.php @@ -8,12 +8,14 @@ namespace MadeYourDay\RockSolidSlider\Module; +@trigger_error('Class MadeYourDay\RockSolidSlider\Module\SliderNews is deprecated and will get removed.', E_USER_DEPRECATED); + /** * Slider News Module * * @author Martin Auswöger */ -class SliderNews extends \ModuleNewsList +class SliderNews extends \MadeYourDay\RockSolidSlider\SlideProvider\Bridge\ContaoNews { /** * Get an array of news articles (HTML output) generated by Contao\ModuleNewsList @@ -22,23 +24,11 @@ class SliderNews extends \ModuleNewsList */ public function getNewsArticles() { - $this->news_archives = $this->sortOutProtected(deserialize($this->news_archives)); - - // Return if there are no archives - if (!is_array($this->news_archives) || !count($this->news_archives)) { - return array(); + $slides = parent::getSlides(); + $articles = []; + foreach ($slides as $slide) { + $articles[] = $slide['text']; } - - // Dummy template object to retrive data from the compile method - $this->Template = new \stdClass; - $this->perPage = 0; - - $this->compile(); - - if (!is_array($this->Template->articles) || !count($this->Template->articles)) { - return array(); - } - - return $this->Template->articles; + return $articles; } } diff --git a/src/Resources/config/model_adapter.yml b/src/Resources/config/model_adapter.yml new file mode 100644 index 0000000..a241f00 --- /dev/null +++ b/src/Resources/config/model_adapter.yml @@ -0,0 +1,21 @@ +services: + + madeyourday.rocksolid_slider.model_adapter.files_model: + class: Contao\CoreBundle\Framework\Adapter + arguments: ['Contao\FilesModel'] + public: false + + madeyourday.rocksolid_slider.model_adapter.module: + class: Contao\CoreBundle\Framework\Adapter + arguments: ['Contao\ModuleModel'] + public: false + + madeyourday.rocksolid_slider.model_adapter.slide_model: + class: Contao\CoreBundle\Framework\Adapter + arguments: ['MadeYourDay\RockSolidSlider\Model\SlideModel'] + public: false + + madeyourday.rocksolid_slider.model_adapter.slider_model: + class: Contao\CoreBundle\Framework\Adapter + arguments: ['MadeYourDay\RockSolidSlider\Model\SliderModel'] + public: false diff --git a/src/Resources/config/services.yml b/src/Resources/config/services.yml new file mode 100644 index 0000000..7f61a43 --- /dev/null +++ b/src/Resources/config/services.yml @@ -0,0 +1,40 @@ +imports: + - { resource: model_adapter.yml } +services: + madeyourday.rocksolid_slider.file_helper: + class: MadeYourDay\RockSolidSlider\Helper\FileHelper + arguments: + - "@madeyourday.rocksolid_slider.model_adapter.files_model" + - "@madeyourday.rocksolid_slider.slideprovider.frontend_adapter" + + madeyourday.rocksolid_slider.slideproviders: + class: MadeYourDay\RockSolidSlider\SlideProvider\SlideProviderRegistry + arguments: [] + + madeyourday.rocksolid_slider.slideprovider.frontend_adapter: + class: Contao\CoreBundle\Framework\Adapter + arguments: ['Contao\Frontend'] + + madeyourday.rocksolid_slider.slideprovider.default: + class: MadeYourDay\RockSolidSlider\SlideProvider\DefaultSlideProvider + arguments: + - "@madeyourday.rocksolid_slider.file_helper" + - "@madeyourday.rocksolid_slider.model_adapter.slider_model" + - "@madeyourday.rocksolid_slider.model_adapter.slide_model" + - "@madeyourday.rocksolid_slider.slideprovider.frontend_adapter" + tags: + - { name: madeyourday.rocksolid_slider.slideprovider } + + madeyourday.rocksolid_slider.slideprovider.events: + class: MadeYourDay\RockSolidSlider\SlideProvider\EventsSlideProvider + arguments: + - "@madeyourday.rocksolid_slider.model_adapter.module" + tags: + - { name: madeyourday.rocksolid_slider.slideprovider } + + madeyourday.rocksolid_slider.slideprovider.news: + class: MadeYourDay\RockSolidSlider\SlideProvider\NewsSlideProvider + arguments: + - "@madeyourday.rocksolid_slider.model_adapter.module" + tags: + - { name: madeyourday.rocksolid_slider.slideprovider } diff --git a/src/RockSolidSliderBundle.php b/src/RockSolidSliderBundle.php index 64018ef..842dbd2 100644 --- a/src/RockSolidSliderBundle.php +++ b/src/RockSolidSliderBundle.php @@ -1,4 +1,5 @@ * @@ -8,13 +9,25 @@ namespace MadeYourDay\RockSolidSlider; +use MadeYourDay\RockSolidSlider\DependencyInjection\Compiler\AddProvidersPass; +use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\HttpKernel\Bundle\Bundle; /** * Configures the RockSolid Slider bundle. * * @author Martin Auswöger + * @author Christian Schiffler */ class RockSolidSliderBundle extends Bundle { + /** + * {@inheritDoc} + */ + public function build(ContainerBuilder $container) + { + parent::build($container); + + $container->addCompilerPass(new AddProvidersPass()); + } } diff --git a/src/SlideProvider/Bridge/ContaoEvents.php b/src/SlideProvider/Bridge/ContaoEvents.php new file mode 100644 index 0000000..45f2be0 --- /dev/null +++ b/src/SlideProvider/Bridge/ContaoEvents.php @@ -0,0 +1,78 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace MadeYourDay\RockSolidSlider\SlideProvider\Bridge; + +/** + * Slider Events Module + * + * @author Christian Schiffler + * @author Martin Auswöger + */ +class ContaoEvents extends \ModuleEventlist +{ + const TEMPLATE_SEPARATOR = ''; + + /** + * Get an array of news articles (HTML output) generated by Contao\ModuleNewsList + * + * @return array + * + * @codeCoverageIgnore - This is simply not testable. :-/ + */ + public function getSlides() + { + $this->cal_calendar = $this->sortOutProtected(deserialize($this->cal_calendar, true)); + + // Return if there are no calendars + if (!is_array($this->cal_calendar) || empty($this->cal_calendar)) { + return array(); + } + + // Dummy template object to retrive data from the compile method + $this->Template = new \stdClass; + $this->perPage = 0; + + $parseTemplateHook = array( + 'MadeYourDay\\RockSolidSlider\\Slider', + 'parseEventsTemplateHook' + ); + // Add the TEMPLATE_SEPARATOR to be able to split the output into single events + $GLOBALS['TL_HOOKS']['parseFrontendTemplate'][] = $parseTemplateHook; + + $this->compile(); + + // Remove the hook + foreach (array_reverse($GLOBALS['TL_HOOKS']['parseFrontendTemplate']) as $key => $hook) { + if ($hook[0] === $parseTemplateHook[0] && $hook[1] === $parseTemplateHook[1]) { + unset($GLOBALS['TL_HOOKS']['parseFrontendTemplate'][$key]); + break; + } + } + + // Split the output into single event items + $eventItems = explode(static::TEMPLATE_SEPARATOR, $this->Template->events); + + if (count($eventItems) < 2) { + // No events found + return array(); + } + + // Remove output before the first event + array_shift($eventItems); + + + $slides = []; + foreach ($eventItems as $newsArticle) { + $slides[] = ['text' => $newsArticle]; + } + + return $slides; + } +} diff --git a/src/SlideProvider/Bridge/ContaoNews.php b/src/SlideProvider/Bridge/ContaoNews.php new file mode 100644 index 0000000..f483ce5 --- /dev/null +++ b/src/SlideProvider/Bridge/ContaoNews.php @@ -0,0 +1,53 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace MadeYourDay\RockSolidSlider\SlideProvider\Bridge; + +/** + * Renders slides from news archives. + * + * @author Christian Schiffler + * @author Martin Auswöger + * + * @codeCoverageIgnore - This is simply not testable. :-/ + */ +class ContaoNews extends \ModuleNewsList +{ + /** + * Get an array of news articles (HTML output) generated by Contao\ModuleNewsList + * + * @return array + */ + public function getSlides() + { + $this->news_archives = $this->sortOutProtected(deserialize($this->news_archives)); + + // Return if there are no archives + if (!is_array($this->news_archives) || !count($this->news_archives)) { + return []; + } + + // Dummy template object to receive data from the compile method + $this->Template = new \stdClass; + $this->perPage = 0; + + $this->compile(); + + if (!is_array($this->Template->articles) || !count($this->Template->articles)) { + return []; + } + + $slides = []; + foreach ($this->Template->articles as $newsArticle) { + $slides[] = ['text' => $newsArticle]; + } + + return $slides; + } +} diff --git a/src/SlideProvider/DefaultSlideProvider.php b/src/SlideProvider/DefaultSlideProvider.php new file mode 100644 index 0000000..f4aee32 --- /dev/null +++ b/src/SlideProvider/DefaultSlideProvider.php @@ -0,0 +1,245 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace MadeYourDay\RockSolidSlider\SlideProvider; + +use Contao\CoreBundle\Framework\Adapter; +use Contao\Frontend; +use Contao\StringUtil; +use MadeYourDay\RockSolidSlider\Helper\FileHelper; +use MadeYourDay\RockSolidSlider\Model\ContentModel; +use MadeYourDay\RockSolidSlider\Model\SlideModel; +use MadeYourDay\RockSolidSlider\Model\SliderModel; +use MadeYourDay\RockSolidSlider\SliderContent; + +/** + * Provides slides from the embedded slide table. + * + * @author Christian Schiffler + */ +class DefaultSlideProvider implements SlideProviderInterface +{ + /** + * @var Adapter|SliderModel + */ + private $sliderModelAdapter; + + /** + * @var Adapter|SlideModel + */ + private $slideModelAdapter; + + /** + * @var Adapter|Frontend + */ + private $frontendAdapter; + + /** + * @var FileHelper + */ + private $fileHelper; + + /** + * Create a new instance. + * + * @param FileHelper $fileHelper + * @param Adapter $sliderModelAdapter + * @param Adapter $slideModelAdapter + * @param Adapter $frontendAdapter + */ + public function __construct( + FileHelper $fileHelper, + Adapter $sliderModelAdapter, + Adapter $slideModelAdapter, + Adapter $frontendAdapter + ) { + $this->fileHelper = $fileHelper; + $this->sliderModelAdapter = $sliderModelAdapter; + $this->slideModelAdapter = $slideModelAdapter; + $this->frontendAdapter = $frontendAdapter; + } + + /** + * {@inheritDoc} + */ + public function getName() + { + return 'rsts_default'; + } + + /** + * {@inheritDoc} + */ + public function process(array $config, SliderContent $content) + { + $slider = $this->sliderModelAdapter->findByPk($config['rsts_id']); + + // Return if there is no slider + if (!$slider || $slider->id !== $config['rsts_id']) { + return; + } + + if ($slider->type === 'image') { + $content->addFiles( + StringUtil::deserialize($slider->multiSRC), + StringUtil::deserialize($slider->orderSRC) ?: [] + ); + + return; + } + + if ($slider->type === 'content') { + $content->addSlides($this->parseSlides($this->slideModelAdapter->findPublishedByPid($slider->id), $config)); + } + } + + /** + * Parse slides + * + * @param \Model\Collection $objSlides slides retrieved from the database + * @param array $config The configuration to process (refer to provider implementation for contents). + * + * @return array parsed slides + */ + private function parseSlides($objSlides, $config) + { + $slides = array(); + $pids = array(); + $idIndexes = array(); + + if (! $objSlides) { + return $slides; + } + + while ($objSlides->next()) { + + $slide = $objSlides->row(); + $slide['text'] = ''; + if ($slide['type'] === 'content') { + $pids[] = $slide['id']; + $idIndexes[(int)$slide['id']] = count($slides); + } + + if (in_array($slide['type'], ['image', 'video'])) { + $slide['image'] = $this->fileHelper->tryPrepareImage( + $slide['singleSRC'], + ['size' => isset($config['imgSize']) ? $config['imgSize'] : $config['size']], + true + ); + } + + if ($slide['type'] === 'video' && $slide['videoURL'] && empty($slide['image'])) { + $slide['image'] = new \stdClass; + if (preg_match( + '(^ + https?:// # http or https + (?: + www\\.youtube\\.com/(?:watch\\?v=|v/|embed/) # Different URL formats + | youtu\\.be/ # Short YouTube domain + ) + ([0-9a-z_\\-]{11}) # YouTube ID + (?:$|&|/) # End or separator + )ix', + html_entity_decode($slide['videoURL']), $matches) + ) { + $video = $matches[1]; + $slide['image']->src = '//img.youtube.com/vi/' . $video . '/0.jpg'; + } + else { + // Grey dummy image + $slide['image']->src = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAJCAMAAAAM9FwAAAAAA1BMVEXGxsbd/8BlAAAAFUlEQVR42s3BAQEAAACAkP6vdiO6AgCZAAG/wrlvAAAAAElFTkSuQmCC'; + } + $slide['image']->imgSize = ''; + $slide['image']->alt = ''; + $slide['image']->picture = [ + 'img' => ['src' => $slide['image']->src, 'srcset' => $slide['image']->src], + 'sources' => [], + ]; + } + + if ($slide['type'] !== 'video' && $slide['videoURL']) { + $slide['videoURL'] = ''; + } + + if ($slide['type'] === 'video' && $slide['videos']) { + $videoFiles = deserialize($slide['videos'], true); + $videoFiles = $this->fileHelper->findMultipleFilesByUuids($videoFiles); + $videos = []; + foreach ($videoFiles as $file) { + $videos[] = $file; + } + $slide['videos'] = $videos; + } + else { + $slide['videos'] = null; + } + + $slide['backgroundImage'] = $this->fileHelper->tryPrepareImage( + $slide['backgroundImage'], + ['size' => $slide['backgroundImageSize']], + true + ); + + if ($slide['backgroundVideos']) { + $videoFiles = deserialize($slide['backgroundVideos'], true); + $videoFiles = $this->fileHelper->findMultipleFilesByUuids($videoFiles); + $videos = array(); + foreach ($videoFiles as $file) { + $videos[] = $file; + } + $slide['backgroundVideos'] = $videos; + } + + if ($config['rsts_navType'] === 'thumbs') { + $slide['thumb'] = $this->generateThumb($slide, $config); + } + + $slides[] = $slide; + + } + + if (count($pids)) { + $slideContents = ContentModel::findPublishedByPidsAndTable($pids, SlideModel::getTable()); + if ($slideContents) { + while ($slideContents->next()) { + $slides[$idIndexes[(int)$slideContents->pid]]['text'] .= + $this->frontendAdapter->getContentElement($slideContents->current()); + } + } + } + + return $slides; + } + + /** + * Generate the thumbnail for a slide. + * + * @param array $slide The slide. + * @param array $config The configuration. + * + * @return \stdClass + */ + private function generateThumb($slide, $config) + { + if ($thumb = $this->fileHelper->tryPrepareImageForTemplate($slide['thumbImage'], ['size' => $config['rsts_thumbs_imgSize']])) { + return $thumb; + } + if (in_array($slide['type'], ['image', 'video']) && + ($thumb = $this->fileHelper->tryPrepareImageForTemplate($slide['singleSRC'], ['size' => $config['rsts_thumbs_imgSize']]))) { + return $thumb; + } + if (!empty($slide['image']->src)) { + return clone $slide['image']; + } + if (!empty($slide['backgroundImage']->src)) { + return clone $slide['backgroundImage']; + } + return $thumb; + } +} diff --git a/src/SlideProvider/EventsSlideProvider.php b/src/SlideProvider/EventsSlideProvider.php new file mode 100644 index 0000000..0f11d07 --- /dev/null +++ b/src/SlideProvider/EventsSlideProvider.php @@ -0,0 +1,68 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace MadeYourDay\RockSolidSlider\SlideProvider; + +use Contao\CoreBundle\Framework\Adapter; +use MadeYourDay\RockSolidSlider\SlideProvider\Bridge\ContaoEvents; +use MadeYourDay\RockSolidSlider\SliderContent; + +/** + * Provides slides from events archives. + * + * @author Christian Schiffler + */ +class EventsSlideProvider implements SlideProviderInterface +{ + /** + * @var Adapter|\Contao\ModuleModel + */ + private $modelAdapter; + + /** + * Create a new instance. + * + * @param Adapter $modelAdapter + */ + public function __construct(Adapter $modelAdapter) + { + $this->modelAdapter = $modelAdapter; + } + + /** + * {@inheritDoc} + */ + public function getName() + { + return 'rsts_events'; + } + + /** + * {@inheritDoc} + */ + public function process(array $config, SliderContent $content) + { + $bridge = $this->getBridge($this->modelAdapter->findByPk($config['id']), $config['slider-column']); + + $content->addSlides($bridge->getSlides()); + } + + /** + * Initialize the bridge. + * + * @param \Contao\ModuleModel $module + * @param string $column + * + * @return ContaoEvents + */ + protected function getBridge($module, $column) + { + return new ContaoEvents($module, $column); + } +} diff --git a/src/SlideProvider/ImageSlideProvider.php b/src/SlideProvider/ImageSlideProvider.php new file mode 100644 index 0000000..f3208ae --- /dev/null +++ b/src/SlideProvider/ImageSlideProvider.php @@ -0,0 +1,37 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace MadeYourDay\RockSolidSlider\SlideProvider; + +use Contao\StringUtil; +use MadeYourDay\RockSolidSlider\SliderContent; + +/** + * Provides files. + * + * @author Christian Schiffler + */ +class ImageSlideProvider implements SlideProviderInterface +{ + /** + * {@inheritDoc} + */ + public function getName() + { + return 'rsts_images'; + } + + /** + * {@inheritDoc} + */ + public function process(array $config, SliderContent $content) + { + $content->addFiles(StringUtil::deserialize($config['multiSRC'])); + } +} diff --git a/src/SlideProvider/NewsSlideProvider.php b/src/SlideProvider/NewsSlideProvider.php new file mode 100644 index 0000000..75e4a02 --- /dev/null +++ b/src/SlideProvider/NewsSlideProvider.php @@ -0,0 +1,68 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace MadeYourDay\RockSolidSlider\SlideProvider; + +use Contao\CoreBundle\Framework\Adapter; +use MadeYourDay\RockSolidSlider\SlideProvider\Bridge\ContaoNews; +use MadeYourDay\RockSolidSlider\SliderContent; + +/** + * Provides slides from news archives. + * + * @author Christian Schiffler + */ +class NewsSlideProvider implements SlideProviderInterface +{ + /** + * @var Adapter|\Contao\ModuleModel + */ + private $modelAdapter; + + /** + * Create a new instance. + * + * @param Adapter $modelAdapter + */ + public function __construct(Adapter $modelAdapter) + { + $this->modelAdapter = $modelAdapter; + } + + /** + * {@inheritDoc} + */ + public function getName() + { + return 'rsts_news'; + } + + /** + * {@inheritDoc} + */ + public function process(array $config, SliderContent $content) + { + $bridge = $this->getBridge($this->modelAdapter->findByPk($config['id']), $config['slider-column']); + + $content->addSlides($bridge->getSlides()); + } + + /** + * Initialize the bridge. + * + * @param \Contao\ModuleModel $module + * @param string $column + * + * @return ContaoNews + */ + protected function getBridge($module, $column) + { + return new ContaoNews($module, $column); + } +} diff --git a/src/SlideProvider/SlideProviderInterface.php b/src/SlideProvider/SlideProviderInterface.php new file mode 100644 index 0000000..f929633 --- /dev/null +++ b/src/SlideProvider/SlideProviderInterface.php @@ -0,0 +1,37 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace MadeYourDay\RockSolidSlider\SlideProvider; + +use MadeYourDay\RockSolidSlider\SliderContent; + +/** + * Describes a generic slide provider. + * + * @author Christian Schiffler + */ +interface SlideProviderInterface +{ + /** + * Retrieve the name of the provider. + * + * @return string + */ + public function getName(); + + /** + * Process the passed configuration. + * + * @param array $config The configuration to process (refer to provider implementation for contents). + * @param SliderContent $content The content to populate. + * + * @return void + */ + public function process(array $config, SliderContent $content); +} diff --git a/src/SlideProvider/SlideProviderRegistry.php b/src/SlideProvider/SlideProviderRegistry.php new file mode 100644 index 0000000..ab1d6df --- /dev/null +++ b/src/SlideProvider/SlideProviderRegistry.php @@ -0,0 +1,77 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace MadeYourDay\RockSolidSlider\SlideProvider; + +/** + * The registry for slide providers. + * + * @author Christian Schiffler + */ +class SlideProviderRegistry +{ + /** + * Registered providers by type as key and instance as value. + * + * @var SlideProviderInterface[] + */ + private $providers = []; + + /** + * Create a new instance. + * + * @param SlideProviderInterface[] $providers + */ + public function __construct(array $providers = []) + { + foreach ($providers as $provider) { + $this->addProvider($provider); + } + } + + /** + * Add a provider. + * + * @param SlideProviderInterface $provider The provider to add. + * + * @return void + */ + public function addProvider(SlideProviderInterface $provider) + { + $this->providers[(string) $provider->getName()] = $provider; + } + + /** + * Retrieve the provider by name. + * + * @param string $name The provider to retrieve. + * + * @return bool + */ + public function hasProvider($name) + { + return isset($this->providers[(string) $name]); + } + + /** + * Retrieve the provider by name. + * + * @param string $name The provider to retrieve. + * + * @return SlideProviderInterface + */ + public function getProvider($name) + { + if (!$this->hasProvider($name)) { + throw new \InvalidArgumentException('No provider with the name ' . $name); + } + + return $this->providers[(string) $name]; + } +} diff --git a/src/SliderContent.php b/src/SliderContent.php new file mode 100644 index 0000000..ec7c208 --- /dev/null +++ b/src/SliderContent.php @@ -0,0 +1,124 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace MadeYourDay\RockSolidSlider; + +/** + * This class holds the slider contents. + * + * @author Christian Schiffler + */ +class SliderContent +{ + /** + * The parsed slides. + * + * @var array + */ + private $slides = []; + + /** + * The uuids of the files to add. + * + * @var string[] + */ + private $files = []; + + /** + * The file order. + * + * @var string[] + */ + private $filesOrder = []; + + /** + * Add slides. + * + * Each slide must at least contain the key 'text'. + * + * @param array $slides The slides to add. + * + * @return void + */ + public function addSlides($slides) + { + foreach ($slides as $slide) { + if (!isset($slide['text'])) { + throw new \InvalidArgumentException('Slide does not contain key "text".'); + } + $this->slides[] = $slide; + } + } + + /** + * Check if slides are contained. + * + * @return bool + */ + public function hasSlides() + { + return (bool) $this->slides; + } + + /** + * Retrieve the slides. + * + * @return array + */ + public function getSlides() + { + return $this->slides; + } + + /** + * Add files to the content. + * + * @param string[] $files The uuids. + * @param string[] $filesOrder The uuids for sort order. + * + * @return void + */ + public function addFiles(array $files, array $filesOrder = []) + { + $this->files = array_merge($this->files, array_values($files)); + if (!empty($this->filesOrder) || empty($filesOrder)) { + $this->filesOrder = array_merge($this->filesOrder, array_values($filesOrder ?: $files)); + } + } + + /** + * Check if files are contained. + * + * @return bool + */ + public function hasFiles() + { + return (bool) $this->files; + } + + /** + * Retrieve the files. + * + * @return array + */ + public function getFiles() + { + return $this->files; + } + + /** + * Retrieve the files. + * + * @return array + */ + public function getFilesOrder() + { + return $this->filesOrder; + } +} diff --git a/tests/DependencyInjection/Compiler/AddProvidersPassTest.php b/tests/DependencyInjection/Compiler/AddProvidersPassTest.php new file mode 100644 index 0000000..4c809ba --- /dev/null +++ b/tests/DependencyInjection/Compiler/AddProvidersPassTest.php @@ -0,0 +1,114 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace MadeYourDay\RockSolidSlider\Test\DependencyInjection\Compiler; + +use MadeYourDay\RockSolidSlider\DependencyInjection\Compiler\AddProvidersPass; +use PHPUnit\Framework\TestCase; +use Symfony\Component\DependencyInjection\ContainerBuilder; +use Symfony\Component\DependencyInjection\Definition; +use Symfony\Component\DependencyInjection\Reference; + +/** + * Tests the AddProvidersPass class. + * + * @author Christian Schiffler + */ +class AddProvidersPassTest extends TestCase +{ + /** + * Tests the object instantiation. + * + * @coversNothing + */ + public function testInstantiation() + { + $pass = new AddProvidersPass(); + + $this->assertInstanceOf('MadeYourDay\RockSolidSlider\DependencyInjection\Compiler\AddProvidersPass', $pass); + } + + /** + * Test the processing. + * + * @return void + * + * @covers \MadeYourDay\RockSolidSlider\DependencyInjection\Compiler\AddProvidersPass::process() + * @covers \MadeYourDay\RockSolidSlider\DependencyInjection\Compiler\AddProvidersPass::getProviders() + */ + public function testProcess() + { + $container = new ContainerBuilder(); + + $mock1 = new Reference('foo'); + + $container->setDefinition( + 'madeyourday.rocksolid_slider.slideproviders', + $registry = new Definition('', [[$mock1]]) + ); + + $tagged1 = new Definition('Tagged1'); + $tagged1->addTag('madeyourday.rocksolid_slider.slideprovider'); + $tagged2 = new Definition('Tagged1'); + $tagged2->addTag('madeyourday.rocksolid_slider.slideprovider'); + + $container->setDefinition('tagged1', $tagged1); + $container->setDefinition('tagged2', $tagged2); + + $pass = new AddProvidersPass(); + + $pass->process($container); + + $ids = []; + foreach ($registry->getArguments()[0] as $argument) { + $this->assertInstanceOf(Reference::class, $argument); + $ids[] = (string) $argument; + } + + $this->assertEquals(['foo', 'tagged1', 'tagged2'], $ids); + } + + /** + * Test the processing when no arguments have been provided so far. + * + * @return void + * + * @covers \MadeYourDay\RockSolidSlider\DependencyInjection\Compiler\AddProvidersPass::process() + * @covers \MadeYourDay\RockSolidSlider\DependencyInjection\Compiler\AddProvidersPass::getProviders() + */ + public function testProcessWithoutArguments() + { + $container = new ContainerBuilder(); + + $container->setDefinition( + 'madeyourday.rocksolid_slider.slideproviders', + $registry = new Definition('') + ); + + $tagged1 = new Definition('Tagged1'); + $tagged1->addTag('madeyourday.rocksolid_slider.slideprovider'); + $tagged2 = new Definition('Tagged1'); + $tagged2->addTag('madeyourday.rocksolid_slider.slideprovider'); + + $container->setDefinition('tagged1', $tagged1); + $container->setDefinition('tagged2', $tagged2); + + $pass = new AddProvidersPass(); + + $pass->process($container); + + $ids = []; + foreach ($registry->getArguments()[0] as $argument) { + $this->assertInstanceOf(Reference::class, $argument); + $ids[] = (string) $argument; + } + + $this->assertEquals(['tagged1', 'tagged2'], $ids); + } +} diff --git a/tests/DependencyInjection/RockSolidSliderExtensionTest.php b/tests/DependencyInjection/RockSolidSliderExtensionTest.php new file mode 100644 index 0000000..98545db --- /dev/null +++ b/tests/DependencyInjection/RockSolidSliderExtensionTest.php @@ -0,0 +1,53 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace MadeYourDay\RockSolidSlider\Test\DependencyInjection; + +use MadeYourDay\RockSolidSlider\DependencyInjection\RockSolidSliderExtension; +use PHPUnit\Framework\TestCase; +use Symfony\Component\DependencyInjection\ContainerBuilder; + +/** + * Tests the RockSolidSliderExtension class. + * + * @author Christian Schiffler + */ +class RockSolidSliderExtensionTest extends TestCase +{ + /** + * Tests the object instantiation. + * + * @coversNothing + */ + public function testInstantiation() + { + $extension = new RockSolidSliderExtension(); + + $this->assertInstanceOf('MadeYourDay\RockSolidSlider\DependencyInjection\RockSolidSliderExtension', $extension); + } + + /** + * Tests adding the bundle services to the container. + * + * @covers \MadeYourDay\RockSolidSlider\DependencyInjection\RockSolidSliderExtension::load() + */ + public function testLoad() + { + $container = new ContainerBuilder(); + + $extension = new RockSolidSliderExtension(); + $extension->load([], $container); + + $this->assertSame( + realpath(__DIR__ . '/../../src/Resources/config/services.yml'), + (string) $container->getResources()[0] + ); + $this->assertTrue($container->has('madeyourday.rocksolid_slider.slideproviders')); + } +} diff --git a/tests/Helper/FileHelperTest.php b/tests/Helper/FileHelperTest.php new file mode 100644 index 0000000..e744544 --- /dev/null +++ b/tests/Helper/FileHelperTest.php @@ -0,0 +1,535 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace MadeYourDay\RockSolidSlider\Test\Helper; + +use Contao\CoreBundle\Framework\Adapter; +use Contao\FilesModel; +use MadeYourDay\RockSolidSlider\Helper\FileHelper; +use PHPUnit\Framework\TestCase; +use PHPUnit_Framework_MockObject_MockObject; + +/** + * Tests the FileHelper class. + * + * @author Christian Schiffler + */ +class FileHelperTest extends TestCase +{ + /** + * Tests the object instantiation. + * + * @covers \MadeYourDay\RockSolidSlider\Helper\FileHelper::__construct() + */ + public function testInstantiation() + { + $helper = new FileHelper( + $this->mockAdapter(), + $this->mockAdapter() + ); + + $this->assertInstanceOf('MadeYourDay\RockSolidSlider\Helper\FileHelper', $helper); + } + + /** + * Test the findMultipleFilesByUuids method. + * + * @covers \MadeYourDay\RockSolidSlider\Helper\FileHelper::__construct() + * @covers \MadeYourDay\RockSolidSlider\Helper\FileHelper::findMultipleFilesByUuids() + */ + public function testFindMultipleFilesByUuids() + { + $filesModelAdapter = $this->mockAdapter(['findMultipleByUuids']); + $frontendAdapter = $this->mockAdapter(); + + $collection = $this + ->getMockBuilder('\Contao\Model\Collection') + ->disableOriginalConstructor() + ->getMock(); + + $filesModelAdapter + ->expects($this->once()) + ->method('findMultipleByUuids') + ->with(['uuid1', 'uuid2'], ['option1' => 'value1', 'option2' => 'value2']) + ->willReturn($collection); + + $helper = new FileHelper($filesModelAdapter, $frontendAdapter); + + $this->assertSame( + $collection, + $helper->findMultipleFilesByUuids( + ['uuid1', 'uuid2'], + ['option1' => 'value1', 'option2' => 'value2'] + ) + ); + } + + /** + * Test the findMultipleFilesByUuidRecursive method. + * + * @covers \MadeYourDay\RockSolidSlider\Helper\FileHelper::__construct() + * @covers \MadeYourDay\RockSolidSlider\Helper\FileHelper::findMultipleFilesByUuids() + * @covers \MadeYourDay\RockSolidSlider\Helper\FileHelper::findMultipleFilesByUuidRecursive() + * + * @return void + */ + public function testFindMultipleFilesByUuidRecursive() + { + $filesModelAdapter = $this->mockAdapter(['findMultipleByUuids', 'getTable', 'findBy']); + $frontendAdapter = $this->mockAdapter(); + + $filesModelAdapter->method('getTable')->willReturn('tl_files'); + + $initial = ['uuid1', 'uuid2']; + + $helper = $this + ->getMockBuilder(FileHelper::class) + ->setConstructorArgs([$filesModelAdapter, $frontendAdapter]) + ->setMethods(['findMultipleFilesByUuids', 'findMultipleFilesByPidRecursive']) + ->getMock(); + $helper->expects($this->once()) + ->method('findMultipleFilesByUuids') + ->with($initial) + ->willReturn([ + $file1 = $this->mockFileModel(['uuid' => 'uuid1', 'pid' => null, 'type' => 'file']), + $this->mockFileModel(['uuid' => 'uuid2', 'pid' => null, 'type' => 'folder']), + ]); + $helper->expects($this->once()) + ->method('findMultipleFilesByPidRecursive') + ->with(['uuid2']) + ->willReturn([ + $file3 = $this->mockFileModel(['uuid' => 'uuid3', 'pid' => 'uuid2', 'type' => 'file']), + $file4 = $this->mockFileModel(['uuid' => 'uuid4', 'pid' => 'uuid2', 'type' => 'file']), + ]); + + /** @var FileHelper $helper */ + $this->assertEquals([$file1, $file3, $file4], $helper->findMultipleFilesByUuidRecursive($initial)); + } + + /** + * Test the findMultipleFilesByUuidRecursive method. + * + * @covers \MadeYourDay\RockSolidSlider\Helper\FileHelper::__construct() + * @covers \MadeYourDay\RockSolidSlider\Helper\FileHelper::findMultipleFilesByUuids() + * @covers \MadeYourDay\RockSolidSlider\Helper\FileHelper::findMultipleFilesByUuidRecursive() + * + * @return void + */ + public function testFindMultipleFilesByUuidRecursive2() + { + $filesModelAdapter = $this->mockAdapter(['findMultipleByUuids', 'getTable', 'findBy']); + $frontendAdapter = $this->mockAdapter(); + + $filesModelAdapter->method('getTable')->willReturn('tl_files'); + + $initial = ['uuid1', 'uuid2']; + + $helper = $this + ->getMockBuilder(FileHelper::class) + ->setConstructorArgs([$filesModelAdapter, $frontendAdapter]) + ->setMethods(['findMultipleFilesByUuids', 'findMultipleFilesByPidRecursive']) + ->getMock(); + $helper->expects($this->once()) + ->method('findMultipleFilesByUuids') + ->with($initial) + ->willReturn([ + $file1 = $this->mockFileModel(['uuid' => 'uuid1', 'pid' => null, 'type' => 'file']), + $file2 = $this->mockFileModel(['uuid' => 'uuid2', 'pid' => null, 'type' => 'file']), + ]); + $helper->expects($this->never()) + ->method('findMultipleFilesByPidRecursive'); + + /** @var FileHelper $helper */ + $this->assertEquals([$file1, $file2], $helper->findMultipleFilesByUuidRecursive($initial)); + } + + /** + * Test the findMultipleFilesByPidRecursive method. + * + * @covers \MadeYourDay\RockSolidSlider\Helper\FileHelper::__construct() + * @covers \MadeYourDay\RockSolidSlider\Helper\FileHelper::findMultipleFilesByUuids() + * @covers \MadeYourDay\RockSolidSlider\Helper\FileHelper::findMultipleFilesByPidRecursive() + * + * @return void + */ + public function testFindMultipleFilesByPidRecursive() + { + $filesModelAdapter = $this->mockAdapter(['getTable', 'findBy']); + $frontendAdapter = $this->mockAdapter(); + + $file3 = $this->mockFileModel(['uuid' => 'uuid3', 'pid' => 'uuid1', 'type' => 'folder']); + $file4 = $this->mockFileModel(['uuid' => 'uuid4', 'pid' => 'uuid1', 'type' => 'file']); + $file5 = $this->mockFileModel(['uuid' => 'uuid4', 'pid' => 'uuid1', 'type' => 'file']); + + $filesModelAdapter->method('getTable')->willReturn('tl_files'); + + $initial = ['uuid1', 'uuid2']; + + $filesModelAdapter->method('findBy') + ->withConsecutive( + [ + ['tl_files.pid IN (UNHEX(?),UNHEX(?))'], + [bin2hex('uuid1'), bin2hex('uuid2')], + [] + ], + [ + ['tl_files.pid IN (UNHEX(?))'], + [bin2hex('uuid3')], + [] + ] + ) + ->willReturnOnConsecutiveCalls( + [$file3, $file4], + [$file5] + ); + + $helper = new FileHelper($filesModelAdapter, $frontendAdapter); + + /** @var FileHelper $helper */ + $this->assertEquals([$file4, $file5], $helper->findMultipleFilesByPidRecursive($initial)); + } + + /** + * Test the prepareImageForTemplate method. + * + * @return void + * + * @covers \MadeYourDay\RockSolidSlider\Helper\FileHelper::__construct() + * @covers \MadeYourDay\RockSolidSlider\Helper\FileHelper::prepareImageForTemplate() + */ + public function testPrepareImageForTemplate() + { + $filesModelAdapter = $this->mockAdapter(); + $frontendAdapter = $this->mockAdapter(['addImageToTemplate']); + $frontendAdapter + ->expects($this->once()) + ->method('addImageToTemplate') + ->with(new \stdClass, ['option1' => 'value1', 'option2' => 'value2']); + + $helper = new FileHelper($filesModelAdapter, $frontendAdapter); + + $helper->prepareImageForTemplate(['option1' => 'value1', 'option2' => 'value2']); + } + + /** + * Test the tryPrepareImage method. + * + * @return void + * + * @covers \MadeYourDay\RockSolidSlider\Helper\FileHelper::__construct() + * @covers \MadeYourDay\RockSolidSlider\Helper\FileHelper::prepareImageForTemplate() + * @covers \MadeYourDay\RockSolidSlider\Helper\FileHelper::tryPrepareImage() + * @covers \MadeYourDay\RockSolidSlider\Helper\FileHelper::tryPrepareImageForTemplate() + * @covers \MadeYourDay\RockSolidSlider\Helper\FileHelper::ensureFileModel() + */ + public function testTryPrepareImageForTemplate() + { + $GLOBALS['objPage'] = (object) ['language' => 'en_EN']; + + $filesModelAdapter = $this->mockAdapter(['findByUuid']); + $frontendAdapter = $this->mockAdapter(['getMetaData', 'addImageToTemplate']); + + $fileModelMock = (object) [ + 'id' => 1, + 'uuid' => 'the-uuid', + 'path' => 'some/path/file.ext', + 'meta' => ['file-meta-data'] + ]; + $fileMock = (object) [ + 'uuid' => 'the-uuid', + 'path' => 'some/path/file.ext', + 'basename' => 'file.ext', + 'isGdImage' => true, + 'isImage' => true, + ]; + + $filesModelAdapter + ->expects($this->once()) + ->method('findByUuid') + ->with('the-uuid') + ->willReturn($fileModelMock); + + $frontendAdapter + ->expects($this->once()) + ->method('getMetaData') + ->with(['file-meta-data'], 'en_EN') + ->willReturn([ + 'title' => 'Title', + 'link' => 'https://example.org', + 'caption' => 'File caption!' + ]); + $frontendAdapter + ->expects($this->once()) + ->method('addImageToTemplate') + ->with( + new \stdClass, + [ + 'id' => 1, + 'uuid' => 'the-uuid', + 'name' => 'file.ext', + 'singleSRC' => 'some/path/file.ext', + 'additional' => 'attribute', + 'alt' => 'Title', + 'imageUrl' => 'https://example.org', + 'caption' => 'File caption!' + ] + ) + ->willReturnCallback(function ($image) { $image->result = 'Success!';}); + + $helper = $this + ->getMockBuilder(FileHelper::class) + ->setConstructorArgs([$filesModelAdapter, $frontendAdapter]) + ->setMethods(['getFileInstance']) + ->getMock(); + $helper + ->expects($this->once()) + ->method('getFileInstance') + ->with($fileModelMock->path) + ->willReturn($fileMock); + + /** @var FileHelper $helper */ + $this->assertSame( + 'Success!', + $helper->tryPrepareImageForTemplate('the-uuid', ['additional' => 'attribute'], true)->result + ); + } + + /** + * Test the tryPrepareImage method. + * + * @return void + * + * @covers \MadeYourDay\RockSolidSlider\Helper\FileHelper::__construct() + * @covers \MadeYourDay\RockSolidSlider\Helper\FileHelper::tryPrepareImage() + * @covers \MadeYourDay\RockSolidSlider\Helper\FileHelper::tryPrepareImageForTemplate() + * @covers \MadeYourDay\RockSolidSlider\Helper\FileHelper::ensureFileModel() + */ + public function testTryPrepareImageForTemplateWithoutUuid() + { + + $filesModelAdapter = $this->mockAdapter(['findByUuid']); + $frontendAdapter = $this->mockAdapter(['getMetaData', 'addImageToTemplate']); + + $filesModelAdapter + ->expects($this->never()) + ->method('findByUuid'); + $frontendAdapter + ->expects($this->never()) + ->method('getMetaData'); + $frontendAdapter + ->expects($this->never()) + ->method('addImageToTemplate'); + + $helper = $this + ->getMockBuilder(FileHelper::class) + ->setConstructorArgs([$filesModelAdapter, $frontendAdapter]) + ->setMethods(['getFileInstance']) + ->getMock(); + $helper + ->expects($this->never()) + ->method('getFileInstance'); + + /** @var FileHelper $helper */ + $this->assertNull($helper->tryPrepareImageForTemplate('', [])); + } + + /** + * Test the tryPrepareImage method. + * + * @return void + * + * @covers \MadeYourDay\RockSolidSlider\Helper\FileHelper::__construct() + * @covers \MadeYourDay\RockSolidSlider\Helper\FileHelper::prepareImageForTemplate() + * @covers \MadeYourDay\RockSolidSlider\Helper\FileHelper::tryPrepareImage() + * @covers \MadeYourDay\RockSolidSlider\Helper\FileHelper::tryPrepareImageForTemplate() + * @covers \MadeYourDay\RockSolidSlider\Helper\FileHelper::ensureFileModel() + */ + public function testTryPrepareImageForTemplateWithUnknownUuid() + { + + $filesModelAdapter = $this->mockAdapter(['findByUuid']); + $frontendAdapter = $this->mockAdapter(['getMetaData', 'addImageToTemplate']); + + $filesModelAdapter + ->expects($this->once()) + ->method('findByUuid') + ->with('unknown-uuid') + ->willReturn(null); + $frontendAdapter + ->expects($this->never()) + ->method('getMetaData'); + $frontendAdapter + ->expects($this->never()) + ->method('addImageToTemplate'); + + + $helper = $this + ->getMockBuilder(FileHelper::class) + ->setConstructorArgs([$filesModelAdapter, $frontendAdapter]) + ->setMethods(['getFileInstance']) + ->getMock(); + $helper + ->expects($this->never()) + ->method('getFileInstance'); + + /** @var FileHelper $helper */ + $this->assertNull($helper->tryPrepareImageForTemplate('unknown-uuid', [])); + } + + /** + * Test the tryPrepareImage method. + * + * @return void + * + * @covers \MadeYourDay\RockSolidSlider\Helper\FileHelper::__construct() + * @covers \MadeYourDay\RockSolidSlider\Helper\FileHelper::prepareImageForTemplate() + * @covers \MadeYourDay\RockSolidSlider\Helper\FileHelper::tryPrepareImage() + * @covers \MadeYourDay\RockSolidSlider\Helper\FileHelper::tryPrepareImageForTemplate() + * @covers \MadeYourDay\RockSolidSlider\Helper\FileHelper::ensureFileModel() + */ + public function testTryPrepareImageForTemplateWithNonImageUuid() + { + $filesModelAdapter = $this->mockAdapter(['findByUuid']); + $frontendAdapter = $this->mockAdapter(['getMetaData', 'addImageToTemplate']); + + $fileModelMock = (object) [ + 'id' => 1, + 'uuid' => 'the-uuid', + 'path' => 'some/path/file.ext', + 'meta' => ['file-meta-data'] + ]; + $fileMock = (object) [ + 'uuid' => 'the-uuid', + 'path' => 'some/path/file.ext', + 'basename' => 'file.ext', + 'isGdImage' => false, + 'isImage' => false, + ]; + + $filesModelAdapter + ->expects($this->once()) + ->method('findByUuid') + ->with('the-uuid') + ->willReturn($fileModelMock); + + $frontendAdapter + ->expects($this->never()) + ->method('getMetaData'); + $frontendAdapter + ->expects($this->never()) + ->method('addImageToTemplate'); + + $helper = $this + ->getMockBuilder(FileHelper::class) + ->setConstructorArgs([$filesModelAdapter, $frontendAdapter]) + ->setMethods(['getFileInstance']) + ->getMock(); + $helper + ->expects($this->once()) + ->method('getFileInstance') + ->with('some/path/file.ext') + ->willReturn($fileMock); + + /** @var FileHelper $helper */ + $this->assertNull($helper->tryPrepareImageForTemplate('the-uuid', [])); + } + + /** + * Test the ensureFileModel method does try to look up a passed files model again. + * + * @return void + * + * @covers \MadeYourDay\RockSolidSlider\Helper\FileHelper::__construct() + * @covers \MadeYourDay\RockSolidSlider\Helper\FileHelper::tryPrepareImage() + * @covers \MadeYourDay\RockSolidSlider\Helper\FileHelper::ensureFileModel() + */ + public function testEnsureFileModelDoesNotConvertModel() + { + $filesModelAdapter = $this->mockAdapter(['findByUuid']); + $frontendAdapter = $this->mockAdapter(['getMetaData', 'addImageToTemplate']); + $fileModelMock = $this->mockFileModel(['path' => 'some/path/file.ext']); + + $fileMock = (object) [ + 'isGdImage' => false, + 'isImage' => false, + ]; + + $filesModelAdapter + ->expects($this->never()) + ->method('findByUuid'); + + $frontendAdapter + ->expects($this->never()) + ->method('getMetaData'); + $frontendAdapter + ->expects($this->never()) + ->method('addImageToTemplate'); + + $helper = $this + ->getMockBuilder(FileHelper::class) + ->setConstructorArgs([$filesModelAdapter, $frontendAdapter]) + ->setMethods(['getFileInstance']) + ->getMock(); + $helper + ->expects($this->once()) + ->method('getFileInstance') + ->with('some/path/file.ext') + ->willReturn($fileMock); + + /** @var FileHelper $helper */ + $this->assertNull($helper->tryPrepareImage($fileModelMock, [])); + } + + + /** + * Mock an adapter + * + * @param string[] $methods The methods to mock. + * + * @return Adapter|PHPUnit_Framework_MockObject_MockObject + */ + private function mockAdapter($methods = []) + { + return $this + ->getMockBuilder('Contao\CoreBundle\Framework\Adapter') + ->setMethods($methods) + ->disableOriginalConstructor() + ->getMock(); + } + + /** + * Mock a file model. + * + * @param array $data The data to return. + * + * @return FilesModel + */ + private function mockFileModel($data) + { + if (!class_exists('Model')) { + class_alias('Contao\Model', 'Model'); + } + + $fileModelMock = $this + ->getMockBuilder(FilesModel::class) + ->disableOriginalConstructor() + ->setMethods(['__get']) + ->getMock(); + $fileModelMock + ->method('__get') + ->willReturnCallback(function ($key) use ($data) { + if (isset($data[$key])) { + return $data[$key]; + } + return null; + }); + + return $fileModelMock; + } +} diff --git a/tests/RockSolidSliderBundleTest.php b/tests/RockSolidSliderBundleTest.php new file mode 100644 index 0000000..7b53db6 --- /dev/null +++ b/tests/RockSolidSliderBundleTest.php @@ -0,0 +1,76 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace MadeYourDay\RockSolidSlider\Test; + +use MadeYourDay\RockSolidSlider\RockSolidSliderBundle; +use PHPUnit\Framework\TestCase; +use Symfony\Component\DependencyInjection\ContainerBuilder; + +/** + * Tests the RockSolidSliderBundle class. + * + * @author Christian Schiffler + */ +class RockSolidSliderBundleTest extends TestCase +{ + /** + * Tests the object instantiation. + * + * @coversNothing + */ + public function testInstantiation() + { + $bundle = new RockSolidSliderBundle(); + + $this->assertInstanceOf('MadeYourDay\RockSolidSlider\RockSolidSliderBundle', $bundle); + } + + /** + * Tests the getContainerExtension() method. + * + * @covers \MadeYourDay\RockSolidSlider\RockSolidSliderBundle::getContainerExtension() + */ + public function testGetContainerExtension() + { + $bundle = new RockSolidSliderBundle(); + + $this->assertInstanceOf( + 'MadeYourDay\RockSolidSlider\DependencyInjection\RockSolidSliderExtension', + $bundle->getContainerExtension() + ); + } + + /** + * Tests the build() method. + * + * @covers \MadeYourDay\RockSolidSlider\RockSolidSliderBundle::build() + */ + public function testBuild() + { + $container = new ContainerBuilder(); + + $bundle = new RockSolidSliderBundle(); + $bundle->build($container); + + $classes = []; + + foreach ($container->getCompilerPassConfig()->getBeforeOptimizationPasses() as $pass) { + $reflection = new \ReflectionClass($pass); + $classes[] = $reflection->getName(); + } + + $this->assertEquals( + [ + 'MadeYourDay\RockSolidSlider\DependencyInjection\Compiler\AddProvidersPass', + ], + $classes + ); + } +} diff --git a/tests/SlideProvider/DefaultSlideProviderTest.php b/tests/SlideProvider/DefaultSlideProviderTest.php new file mode 100644 index 0000000..ba70180 --- /dev/null +++ b/tests/SlideProvider/DefaultSlideProviderTest.php @@ -0,0 +1,147 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace MadeYourDay\RockSolidSlider\Test\SlideProvider; + +use Contao\CoreBundle\Framework\Adapter; +use MadeYourDay\RockSolidSlider\Helper\FileHelper; +use MadeYourDay\RockSolidSlider\SlideProvider\DefaultSlideProvider; +use MadeYourDay\RockSolidSlider\SliderContent; +use PHPUnit\Framework\TestCase; + +/** + * Tests the DefaultSlideProvider class. + * + * @author Christian Schiffler + */ +class DefaultSlideProviderTest extends TestCase +{ + /** + * Tests the object instantiation. + * + * @covers \MadeYourDay\RockSolidSlider\SlideProvider\DefaultSlideProvider::__construct() + * @covers \MadeYourDay\RockSolidSlider\SlideProvider\DefaultSlideProvider::getName() + */ + public function testInstantiation() + { + $filesHelper = $this->getMockBuilder(FileHelper::class)->disableOriginalConstructor()->getMock(); + $sliderModelAdapter = $this->getMockBuilder(Adapter::class)->disableOriginalConstructor()->getMock(); + $slideModelAdapter = $this->getMockBuilder(Adapter::class)->disableOriginalConstructor()->getMock(); + $frontendAdapter = $this->getMockBuilder(Adapter::class)->disableOriginalConstructor()->getMock(); + + $provider = new DefaultSlideProvider( + $filesHelper, + $sliderModelAdapter, + $slideModelAdapter, + $frontendAdapter + ); + + $this->assertInstanceOf('MadeYourDay\RockSolidSlider\SlideProvider\DefaultSlideProvider', $provider); + $this->assertSame('rsts_default', $provider->getName()); + } + + /** + * Test adding providers. + * + * @return void + * + * @covers \MadeYourDay\RockSolidSlider\SlideProvider\DefaultSlideProvider::__construct() + * @covers \MadeYourDay\RockSolidSlider\SlideProvider\DefaultSlideProvider::process() + * @uses \MadeYourDay\RockSolidSlider\SliderContent::addFiles() + * @uses \MadeYourDay\RockSolidSlider\SliderContent::getFiles() + * @uses \MadeYourDay\RockSolidSlider\SliderContent::hasFiles() + * @uses \MadeYourDay\RockSolidSlider\SliderContent::hasSlides() + * @uses \MadeYourDay\RockSolidSlider\SliderContent::getSlides() + */ + public function testProcessWithoutSlider() + { + $filesHelper = $this->getMockBuilder(FileHelper::class)->disableOriginalConstructor()->getMock(); + $sliderModelAdapter = $this->getMockBuilder(Adapter::class)->setMethods(['findByPk'])->disableOriginalConstructor()->getMock(); + $slideModelAdapter = $this->getMockBuilder(Adapter::class)->disableOriginalConstructor()->getMock(); + $frontendAdapter = $this->getMockBuilder(Adapter::class)->disableOriginalConstructor()->getMock(); + + $sliderModelAdapter + ->expects($this->once()) + ->method('findByPk') + ->willReturn(null); + + $provider = new DefaultSlideProvider( + $filesHelper, + $sliderModelAdapter, + $slideModelAdapter, + $frontendAdapter + ); + $content = new SliderContent(); + + $provider->process(['rsts_id' => 42], $content); + + $this->assertFalse($content->hasSlides()); + $this->assertFalse($content->hasFiles()); + $this->assertSame([], $content->getSlides()); + $this->assertSame([], $content->getFiles()); + } + + /** + * Test adding providers. + * + * @return void + * + * @covers \MadeYourDay\RockSolidSlider\SlideProvider\DefaultSlideProvider::__construct() + * @covers \MadeYourDay\RockSolidSlider\SlideProvider\DefaultSlideProvider::process() + */ + public function testProcessWithImageSlides() + { + $filesHelper = $this->getMockBuilder(FileHelper::class)->disableOriginalConstructor()->getMock(); + $sliderModelAdapter = $this->getMockBuilder(Adapter::class)->setMethods(['findByPk'])->disableOriginalConstructor()->getMock(); + $slideModelAdapter = $this->getMockBuilder(Adapter::class)->disableOriginalConstructor()->getMock(); + $frontendAdapter = $this->getMockBuilder(Adapter::class)->disableOriginalConstructor()->getMock(); + + $sliderModelAdapter + ->expects($this->once()) + ->method('findByPk') + ->willReturn((object) [ + 'id' => 42, + 'type' => 'image', + 'multiSRC' => serialize(['uuid1', 'uuid2']), + 'orderSRC' => serialize(['uuid1', 'uuid2', 'uuid3', 'uuid4']), + ]); + + $provider = new DefaultSlideProvider( + $filesHelper, + $sliderModelAdapter, + $slideModelAdapter, + $frontendAdapter + ); + + new SliderContent(); + + $content = $this->getMockBuilder(SliderContent::class)->setMethods( + [ + 'addFiles', + 'getFiles', + 'hasFiles', + 'hasSlides', + 'getSlides', + 'getFilesOrder', + ] + )->getMock(); + $content->expects($this->once())->method('addFiles')->with( + ['uuid1', 'uuid2'], + ['uuid1', 'uuid2', 'uuid3', 'uuid4'] + ); + $content->expects($this->never())->method('hasFiles'); + $content->expects($this->never())->method('getFiles'); + $content->expects($this->never())->method('getFilesOrder'); + $content->expects($this->never())->method('hasSlides'); + $content->expects($this->never())->method('getSlides'); + $content->expects($this->never())->method('getFiles'); + + $provider->process(['rsts_id' => 42], $content); + } +} diff --git a/tests/SlideProvider/EventsSlideProviderTest.php b/tests/SlideProvider/EventsSlideProviderTest.php new file mode 100644 index 0000000..7c5fa03 --- /dev/null +++ b/tests/SlideProvider/EventsSlideProviderTest.php @@ -0,0 +1,95 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace MadeYourDay\RockSolidSlider\Test\SlideProvider; + +use Contao\CoreBundle\Framework\Adapter; +use Contao\ModuleModel; +use MadeYourDay\RockSolidSlider\SlideProvider\EventsSlideProvider; +use MadeYourDay\RockSolidSlider\SliderContent; +use PHPUnit\Framework\TestCase; + +/** + * Tests the EventsSlideProvider class. + * + * @author Christian Schiffler + */ +class EventsSlideProviderTest extends TestCase +{ + /** + * Tests the object instantiation. + * + * @covers \MadeYourDay\RockSolidSlider\SlideProvider\EventsSlideProvider::__construct() + * @covers \MadeYourDay\RockSolidSlider\SlideProvider\EventsSlideProvider::getName() + */ + public function testInstantiation() + { + $provider = new EventsSlideProvider( + $this->getMockBuilder(Adapter::class)->disableOriginalConstructor()->getMock() + ); + + $this->assertInstanceOf('MadeYourDay\RockSolidSlider\SlideProvider\EventsSlideProvider', $provider); + $this->assertSame('rsts_events', $provider->getName()); + } + + /** + * Test adding providers. + * + * @return void + * + * @covers \MadeYourDay\RockSolidSlider\SlideProvider\EventsSlideProvider::__construct() + * @covers \MadeYourDay\RockSolidSlider\SlideProvider\EventsSlideProvider::process() + * @uses \MadeYourDay\RockSolidSlider\SliderContent::addSlides() + * @uses \MadeYourDay\RockSolidSlider\SliderContent::getSlides() + * @uses \MadeYourDay\RockSolidSlider\SliderContent::hasFiles() + * @uses \MadeYourDay\RockSolidSlider\SliderContent::hasSlides() + */ + public function testProcess() + { + $bridge= $this + ->getMockBuilder(\stdClass::class) + ->setMethods(['getSlides']) + ->disableOriginalConstructor() + ->getMock(); + $bridge->expects($this->once())->method('getSlides')->willReturn([['text' => 'content']]); + + $model = $this->getMockBuilder(ModuleModel::class)->disableOriginalConstructor()->getMock(); + + $adapter = $this + ->getMockBuilder(Adapter::class) + ->setMethods(['findByPk']) + ->disableOriginalConstructor() + ->getMock(); + $adapter + ->expects($this->once()) + ->method('findByPk') + ->with(42) + ->willReturn($model); + + $provider = $this + ->getMockBuilder(EventsSlideProvider::class) + ->setMethods(['getBridge']) + ->setConstructorArgs([$adapter]) + ->getMock(); + $provider + ->expects($this->once()) + ->method('getBridge') + ->with($model, 'main') + ->willReturn($bridge); + + $content = new SliderContent(); + + /** @@var EventsSlideProvider $provider */ + $provider->process(['id' => 42, 'slider-column' => 'main'], $content); + + $this->assertTrue($content->hasSlides()); + $this->assertFalse($content->hasFiles()); + $this->assertSame([['text' => 'content']], $content->getSlides()); + } +} diff --git a/tests/SlideProvider/ImageSlideProviderTest.php b/tests/SlideProvider/ImageSlideProviderTest.php new file mode 100644 index 0000000..e6c9cbc --- /dev/null +++ b/tests/SlideProvider/ImageSlideProviderTest.php @@ -0,0 +1,62 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace MadeYourDay\RockSolidSlider\Test\SlideProvider; + +use Contao\CoreBundle\Framework\Adapter; +use Contao\ModuleModel; +use MadeYourDay\RockSolidSlider\SlideProvider\ImageSlideProvider; +use MadeYourDay\RockSolidSlider\SliderContent; +use PHPUnit\Framework\TestCase; + +/** + * Tests the ImageSlideProvider class. + * + * @author Christian Schiffler + */ +class ImageSlideProviderTest extends TestCase +{ + /** + * Tests the object instantiation. + * + * @covers \MadeYourDay\RockSolidSlider\SlideProvider\ImageSlideProvider::getName() + */ + public function testInstantiation() + { + $provider = new ImageSlideProvider( + $this->getMockBuilder(Adapter::class)->disableOriginalConstructor()->getMock() + ); + + $this->assertInstanceOf('MadeYourDay\RockSolidSlider\SlideProvider\ImageSlideProvider', $provider); + $this->assertSame('rsts_images', $provider->getName()); + } + + /** + * Test adding providers. + * + * @return void + * + * @covers \MadeYourDay\RockSolidSlider\SlideProvider\ImageSlideProvider::process() + * @uses \MadeYourDay\RockSolidSlider\SliderContent::addFiles() + * @uses \MadeYourDay\RockSolidSlider\SliderContent::getFiles() + * @uses \MadeYourDay\RockSolidSlider\SliderContent::hasFiles() + * @uses \MadeYourDay\RockSolidSlider\SliderContent::hasSlides() + */ + public function testProcess() + { + $provider = new ImageSlideProvider(); + $content = new SliderContent(); + + $provider->process(['multiSRC' => serialize(['uuid1', 'uuid2'])], $content); + + $this->assertFalse($content->hasSlides()); + $this->assertTrue($content->hasFiles()); + $this->assertSame(['uuid1', 'uuid2'], $content->getFiles()); + } +} diff --git a/tests/SlideProvider/NewsSlideProviderTest.php b/tests/SlideProvider/NewsSlideProviderTest.php new file mode 100644 index 0000000..25e1014 --- /dev/null +++ b/tests/SlideProvider/NewsSlideProviderTest.php @@ -0,0 +1,95 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace MadeYourDay\RockSolidSlider\Test\SlideProvider; + +use Contao\CoreBundle\Framework\Adapter; +use Contao\ModuleModel; +use MadeYourDay\RockSolidSlider\SlideProvider\NewsSlideProvider; +use MadeYourDay\RockSolidSlider\SliderContent; +use PHPUnit\Framework\TestCase; + +/** + * Tests the NewsSlideProvider class. + * + * @author Christian Schiffler + */ +class NewsSlideProviderTest extends TestCase +{ + /** + * Tests the object instantiation. + * + * @covers \MadeYourDay\RockSolidSlider\SlideProvider\NewsSlideProvider::__construct() + * @covers \MadeYourDay\RockSolidSlider\SlideProvider\NewsSlideProvider::getName() + */ + public function testInstantiation() + { + $provider = new NewsSlideProvider( + $this->getMockBuilder(Adapter::class)->disableOriginalConstructor()->getMock() + ); + + $this->assertInstanceOf('MadeYourDay\RockSolidSlider\SlideProvider\NewsSlideProvider', $provider); + $this->assertSame('rsts_news', $provider->getName()); + } + + /** + * Test adding providers. + * + * @return void + * + * @covers \MadeYourDay\RockSolidSlider\SlideProvider\NewsSlideProvider::__construct() + * @covers \MadeYourDay\RockSolidSlider\SlideProvider\NewsSlideProvider::process() + * @uses \MadeYourDay\RockSolidSlider\SliderContent::addSlides() + * @uses \MadeYourDay\RockSolidSlider\SliderContent::getSlides() + * @uses \MadeYourDay\RockSolidSlider\SliderContent::hasFiles() + * @uses \MadeYourDay\RockSolidSlider\SliderContent::hasSlides() + */ + public function testProcess() + { + $bridge= $this + ->getMockBuilder(\stdClass::class) + ->setMethods(['getSlides']) + ->disableOriginalConstructor() + ->getMock(); + $bridge->expects($this->once())->method('getSlides')->willReturn([['text' => 'content']]); + + $model = $this->getMockBuilder(ModuleModel::class)->disableOriginalConstructor()->getMock(); + + $adapter = $this + ->getMockBuilder(Adapter::class) + ->setMethods(['findByPk']) + ->disableOriginalConstructor() + ->getMock(); + $adapter + ->expects($this->once()) + ->method('findByPk') + ->with(42) + ->willReturn($model); + + $provider = $this + ->getMockBuilder(NewsSlideProvider::class) + ->setMethods(['getBridge']) + ->setConstructorArgs([$adapter]) + ->getMock(); + $provider + ->expects($this->once()) + ->method('getBridge') + ->with($model, 'main') + ->willReturn($bridge); + + $content = new SliderContent(); + + /** @@var NewsSlideProvider $provider */ + $provider->process(['id' => 42, 'slider-column' => 'main'], $content); + + $this->assertTrue($content->hasSlides()); + $this->assertFalse($content->hasFiles()); + $this->assertSame([['text' => 'content']], $content->getSlides()); + } +} diff --git a/tests/SlideProvider/SlideProviderRegistryTest.php b/tests/SlideProvider/SlideProviderRegistryTest.php new file mode 100644 index 0000000..8865148 --- /dev/null +++ b/tests/SlideProvider/SlideProviderRegistryTest.php @@ -0,0 +1,105 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace MadeYourDay\RockSolidSlider\Test\SlideProvider; + +use InvalidArgumentException; +use MadeYourDay\RockSolidSlider\SlideProvider\SlideProviderInterface; +use MadeYourDay\RockSolidSlider\SlideProvider\SlideProviderRegistry; +use PHPUnit\Framework\TestCase; + +/** + * Tests the SlideProviderRegistry class. + * + * @author Christian Schiffler + */ +class SlideProviderRegistryTest extends TestCase +{ + /** + * Tests the object instantiation. + * + * @covers \MadeYourDay\RockSolidSlider\SlideProvider\SlideProviderRegistry::__construct() + */ + public function testInstantiation() + { + $registry = new SlideProviderRegistry(); + + $this->assertInstanceOf('MadeYourDay\RockSolidSlider\SlideProvider\SlideProviderRegistry', $registry); + } + + /** + * Test adding providers. + * + * @return void + * + * @covers \MadeYourDay\RockSolidSlider\SlideProvider\SlideProviderRegistry::__construct() + * @covers \MadeYourDay\RockSolidSlider\SlideProvider\SlideProviderRegistry::addProvider() + * @covers \MadeYourDay\RockSolidSlider\SlideProvider\SlideProviderRegistry::getProvider() + * @covers \MadeYourDay\RockSolidSlider\SlideProvider\SlideProviderRegistry::hasProvider() + */ + public function testAddProvider() + { + $registry = new SlideProviderRegistry(); + + $this->assertFalse($registry->hasProvider('test-provider')); + + $mock = $this->getMockForAbstractClass(SlideProviderInterface::class); + $mock->method('getName')->willReturn('test-provider'); + + $registry->addProvider($mock); + + $this->assertTrue($registry->hasProvider('test-provider')); + $this->assertSame($mock, $registry->getProvider('test-provider')); + } + + /** + * Test that the instance get's populated with constructor arguments. + * + * @return void + * + * @covers \MadeYourDay\RockSolidSlider\SlideProvider\SlideProviderRegistry::__construct() + * @covers \MadeYourDay\RockSolidSlider\SlideProvider\SlideProviderRegistry::addProvider() + * @covers \MadeYourDay\RockSolidSlider\SlideProvider\SlideProviderRegistry::getProvider() + * @covers \MadeYourDay\RockSolidSlider\SlideProvider\SlideProviderRegistry::hasProvider() + */ + public function testInitWithProviders() + { + $mock1 = $this->getMockForAbstractClass(SlideProviderInterface::class); + $mock1->method('getName')->willReturn('test-provider1'); + $mock2 = $this->getMockForAbstractClass(SlideProviderInterface::class); + $mock2->method('getName')->willReturn('test-provider2'); + + $registry = new SlideProviderRegistry([$mock1, $mock2]); + + $this->assertTrue($registry->hasProvider('test-provider1')); + $this->assertSame($mock1, $registry->getProvider('test-provider1')); + $this->assertTrue($registry->hasProvider('test-provider2')); + $this->assertSame($mock2, $registry->getProvider('test-provider2')); + } + + + /** + * Test that the instance get's populated with constructor arguments. + * + * @return void + * + * @covers \MadeYourDay\RockSolidSlider\SlideProvider\SlideProviderRegistry::__construct() + * @covers \MadeYourDay\RockSolidSlider\SlideProvider\SlideProviderRegistry::getProvider() + * @covers \MadeYourDay\RockSolidSlider\SlideProvider\SlideProviderRegistry::hasProvider() + */ + public function testRetrieveUnknownProvider() + { + $registry = new SlideProviderRegistry(); + + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage('No provider with the name slide-type'); + + $registry->getProvider('slide-type'); + } +} diff --git a/tests/SliderContentTest.php b/tests/SliderContentTest.php new file mode 100644 index 0000000..bb63ecc --- /dev/null +++ b/tests/SliderContentTest.php @@ -0,0 +1,166 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace MadeYourDay\RockSolidSlider\Test; + +use MadeYourDay\RockSolidSlider\SliderContent; +use PHPUnit\Framework\TestCase; + +/** + * Tests the SliderContent class. + * + * @author Christian Schiffler + */ +class SliderContentTest extends TestCase +{ + /** + * Tests the object instantiation. + * + * @coversNothing + */ + public function testInstantiation() + { + $content = new SliderContent(); + + $this->assertInstanceOf('MadeYourDay\RockSolidSlider\SliderContent', $content); + } + + /** + * Test that empty slides are really empty. + * + * @return void + * + * @covers \MadeYourDay\RockSolidSlider\SliderContent::hasSlides() + * @covers \MadeYourDay\RockSolidSlider\SliderContent::getSlides() + */ + public function testEmptySlides() + { + $content = new SliderContent(); + + $this->assertFalse($content->hasSlides()); + $this->assertEquals([], $content->getSlides()); + } + + /** + * Test that slides can get added and are returned correctly. + * + * @return void + * + * @covers \MadeYourDay\RockSolidSlider\SliderContent::addSlides() + * @covers \MadeYourDay\RockSolidSlider\SliderContent::hasSlides() + * @covers \MadeYourDay\RockSolidSlider\SliderContent::getSlides() + */ + public function testAddSlides() + { + $content = new SliderContent(); + $content->addSlides([ + ['text' => 'slide 1'], + ['text' => 'slide 2'], + ['text' => 'slide 3'], + ]); + $content->addSlides([ + 'some_key' => ['text' => 'slide 4'], + ['text' => 'slide 5'], + ['text' => 'slide 6'], + ]); + + $this->assertTrue($content->hasSlides()); + $this->assertEquals( + [ + ['text' => 'slide 1'], + ['text' => 'slide 2'], + ['text' => 'slide 3'], + ['text' => 'slide 4'], + ['text' => 'slide 5'], + ['text' => 'slide 6'], + ], + $content->getSlides() + ); + } + + /** + * Test that invalid slides can not get added. + * + * @return void + * + * @covers \MadeYourDay\RockSolidSlider\SliderContent::addSlides() + */ + public function testAddInvalidSlide() + { + $content = new SliderContent(); + $this->expectException('\InvalidArgumentException'); + $this->expectExceptionMessage('Slide does not contain key "text".'); + $content->addSlides([['invalid' => 'slide']]); + } + + /** + * Test that empty files are really empty. + * + * @return void + * + * @covers \MadeYourDay\RockSolidSlider\SliderContent::hasFiles() + * @covers \MadeYourDay\RockSolidSlider\SliderContent::getFiles() + */ + public function testEmptyFiles() + { + $content = new SliderContent(); + + $this->assertFalse($content->hasFiles()); + $this->assertEquals([], $content->getFiles()); + } + + /** + * Test that files can get added and are returned correctly. + * + * @return void + * + * @covers \MadeYourDay\RockSolidSlider\SliderContent::addFiles() + * @covers \MadeYourDay\RockSolidSlider\SliderContent::hasFiles() + * @covers \MadeYourDay\RockSolidSlider\SliderContent::getFiles() + * @covers \MadeYourDay\RockSolidSlider\SliderContent::getFilesOrder() + */ + public function testAddFiles() + { + $content = new SliderContent(); + $content->addFiles(['file 1', 'file 2', 'file 3']); + $content->addFiles(['file 4', 'file 5', 'file 6']); + + $this->assertTrue($content->hasFiles()); + $this->assertEquals( + ['file 1', 'file 2', 'file 3', 'file 4', 'file 5', 'file 6'], + $content->getFiles() + ); + $this->assertEquals( + ['file 1', 'file 2', 'file 3', 'file 4', 'file 5', 'file 6'], + $content->getFilesOrder() + ); + } + + /** + * Test that files preserve order. + * + * @return void + * + * @covers \MadeYourDay\RockSolidSlider\SliderContent::addFiles() + * @covers \MadeYourDay\RockSolidSlider\SliderContent::hasFiles() + * @covers \MadeYourDay\RockSolidSlider\SliderContent::getFilesOrder() + */ + public function testAddPreservesOrder() + { + $content = new SliderContent(); + $content->addFiles(['file 1', 'file 2', 'file 3']); + $content->addFiles(['file 4', 'file 5', 'file 6'], ['file 6', 'file 4', 'file 5']); + + $this->assertEquals( + ['file 1', 'file 2', 'file 3', 'file 6', 'file 4', 'file 5'], + $content->getFilesOrder() + ); + } + +}