diff --git a/.gitignore b/.gitignore index a11232f..1859c6a 100644 --- a/.gitignore +++ b/.gitignore @@ -12,3 +12,7 @@ .sass-cache node_modules bower_components +composer.lock +package-lock.json +web +vendor diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..906876e --- /dev/null +++ b/.travis.yml @@ -0,0 +1,44 @@ +dist: trusty +sudo: false +language: php + +cache: + directories: + - $HOME/.composer/cache + +install: + - composer require typo3/cms="$TYPO3_VERSION" + +jobs: + include: + - php: 7.1 + env: TYPO3_VERSION=^8.7 + - php: 7.2 + env: TYPO3_VERSION=^8.7 + + - stage: test + script: + - composer lint + - composer cgl + - composer test + + - stage: deploy + if: tag IS present + php: 7.1 + before_install: skip + install: skip + before_script: skip + script: | + echo -e "Preparing upload of release ${TRAVIS_TAG} to TER\n" + + TAG_ANNOTATION="$(git tag -n -l $TRAVIS_TAG)" + TAG_MESSAGE="${TAG_ANNOTATION#* }" + + git reset --hard + git clean -xfd + + export PATH=$PATH:$(composer global config bin-dir --absolute 2>/dev/null) + composer global require helhum/ter-client dev-master + + echo "Uploading release ${TRAVIS_TAG} to TER" + ter-client upload $(composer config extra.typo3/cms.extension-key) . -u "$TYPO3_ORG_USERNAME" -p "$TYPO3_ORG_PASSWORD" -m "$TAG_MESSAGE" diff --git a/Classes/Domain/Finishers/MjmlEmailFinisher.php b/Classes/Domain/Finishers/MjmlEmailFinisher.php index 6fd9876..a2321f9 100644 --- a/Classes/Domain/Finishers/MjmlEmailFinisher.php +++ b/Classes/Domain/Finishers/MjmlEmailFinisher.php @@ -1,20 +1,6 @@ getEscapedCommand($cmd, $args), $result, $returnValue); + + GeneralUtility::unlink_tempfile($temporaryMjmlFileWithPath); + + return implode('', $result); + } + + /** + * @param string $cmd + * @param string $args + * @return string + */ + protected function getEscapedCommand(string $cmd, string $args) + { + $escapedCmd = escapeshellcmd($cmd); + + $argsArray = explode(' ', $args); + $escapedArgsArray = CommandUtility::escapeShellArguments($argsArray); + $escapedArgs = implode(' ', $escapedArgsArray); + + return $escapedCmd . ' ' . $escapedArgs; + } +} diff --git a/Classes/Domain/Renderer/RendererInterface.php b/Classes/Domain/Renderer/RendererInterface.php new file mode 100644 index 0000000..5cef1b2 --- /dev/null +++ b/Classes/Domain/Renderer/RendererInterface.php @@ -0,0 +1,16 @@ +getHtmlFromMjml(parent::render()); + parent::__construct($contentObject); + + $this->renderer = $renderer; + if ($this->renderer === null) { + $this->renderer = $this->objectManager->get(RendererInterface::class); + } } - protected function getHtmlFromMjml($mjml) + public function render($actionName = null) { - $configuration = unserialize($GLOBALS['TYPO3_CONF_VARS']['EXT']['extConf']['mjml']); - - $temporaryMjmlFileWithPath = GeneralUtility::tempnam('mjml_', '.mjml'); - $mjmlFile = fopen($temporaryMjmlFileWithPath, 'w'); - fwrite($mjmlFile, $mjml); - fclose($mjmlFile); - - // see https://mjml.io/download and https://www.npmjs.com/package/mjml-cli - $cmd = $configuration['nodeBinaryPath'] . ' ' . $configuration['mjmlBinaryPath'] . $configuration['mjmlBinary'] .' ' . $configuration['mjmlParams'] . ' ' . $temporaryMjmlFileWithPath; - - $result = []; - $returnValue = ''; - CommandUtility::exec($cmd, $result, $returnValue); - - return implode('',$result); + return $this->renderer->getHtmlFromMjml(parent::render($actionName)); } } diff --git a/Tests/Unit/AbstractUnitTestCase.php b/Tests/Unit/AbstractUnitTestCase.php new file mode 100644 index 0000000..814e944 --- /dev/null +++ b/Tests/Unit/AbstractUnitTestCase.php @@ -0,0 +1,22 @@ +setCacheConfigurations([ + 'extbase_object' => [ + 'backend' => NullBackend::class, + ], + ]); + } +} diff --git a/Tests/Unit/Domain/Renderer/CommandTest.php b/Tests/Unit/Domain/Renderer/CommandTest.php new file mode 100644 index 0000000..aa7a7fb --- /dev/null +++ b/Tests/Unit/Domain/Renderer/CommandTest.php @@ -0,0 +1,66 @@ + + + + + + + Easy and Quick + + + + Responsive + + + + + Discover + + + + + +'; + + public function setUp() + { + parent::setUp(); + $this->objectManager = GeneralUtility::makeInstance(ObjectManager::class); + } + + /** + * @test + */ + public function htmlIsReturnedForMjml() + { + $expectedHtml = '
Easy and Quick
Responsive

Discover

'; + $GLOBALS['TYPO3_CONF_VARS']['EXT']['extConf']['mjml'] = serialize([ + 'nodeBinaryPath' => 'node', + 'mjmlBinaryPath' => 'node_modules/.bin/', + 'mjmlBinary' => 'mjml', + 'mjmlParams' => '-s -m', + ]); + + $subject = $this->objectManager->get(Command::class); + $html = $subject->getHtmlFromMjml(static::EXAMPLE_MJML_TEMPLATE); + $this->assertSame( + $expectedHtml, + $html, + 'Command renderer did not return expected HTML.' + ); + } +} diff --git a/Tests/Unit/View/MjmlBasedViewTest.php b/Tests/Unit/View/MjmlBasedViewTest.php new file mode 100644 index 0000000..5648444 --- /dev/null +++ b/Tests/Unit/View/MjmlBasedViewTest.php @@ -0,0 +1,55 @@ + + + + + + + Easy and Quick + + + + Responsive + + + + + Discover + + + + + +'; + + /** + * @test + */ + public function viewCallsRendererAndReturnsRenderedHtml() + { + $expectedHtml = '

Simple HTML

'; + $rendererMock = $this->getMockBuilder(RendererInterface::class)->getMock(); + $rendererMock->expects($this->once()) + ->method('getHtmlFromMjml') + ->with(static::EXAMPLE_MJML_TEMPLATE) + ->willReturn($expectedHtml); + + $subject = new MjmlBasedView(null, $rendererMock); + $subject->setTemplateSource(static::EXAMPLE_MJML_TEMPLATE); + $result = $subject->render(); + + $this->assertSame( + $expectedHtml, + $result, + 'Rendering of view did not return expected HTML.' + ); + } +} diff --git a/composer.json b/composer.json index ddbff51..a7649a4 100644 --- a/composer.json +++ b/composer.json @@ -10,13 +10,45 @@ "Saccas\\Mjml\\": "Classes/" } }, + "autoload-dev": { + "psr-4": { + "Saccas\\Mjml\\Tests\\": "Tests/" + } + }, "require": { "php": ">=7.0.0 <=7.2.99", - "typo3/cms-core": ">=8.7.0,<8.9.99" + "typo3/cms-core": "^8.7.0", + "typo3/cms-form": "^8.7.0" + }, + "require-dev": { + "squizlabs/php_codesniffer": "^3.2.0", + "typo3/cms": "^8.7.0", + "typo3/testing-framework": "^1.2.2" }, "scripts": { + "lint": [ + "! find Classes -type f -name \"*.php\" -exec php -d error_reporting=32767 -l {} \\; 2>&1 >&- | grep \"^\"", + "! find Tests -type f -name \"*.php\" -exec php -d error_reporting=32767 -l {} \\; 2>&1 >&- | grep \"^\"" + ], + "cgl": [ + "./vendor/bin/phpcs" + ], + "test": [ + "TYPO3_PATH_ROOT=web ./vendor/bin/phpunit" + ], "post-install-cmd": [ "npm install" ] + }, + "replace": { + "mjml": "self.version", + "typo3-ter/mjml": "self.version" + }, + "extra": { + "typo3/cms": { + "extension-key": "mjml", + "cms-package-dir": "{$vendor-dir}/typo3/cms", + "web-dir": "web" + } } } diff --git a/phpcs.xml.dist b/phpcs.xml.dist new file mode 100644 index 0000000..61e813a --- /dev/null +++ b/phpcs.xml.dist @@ -0,0 +1,17 @@ + + + The coding standard for this extension. + + ./Classes/ + + + + + + + + + + + + diff --git a/phpunit.xml.dist b/phpunit.xml.dist new file mode 100644 index 0000000..f8dad0b --- /dev/null +++ b/phpunit.xml.dist @@ -0,0 +1,28 @@ + + + + + ./Tests/Unit + + + + + + ./Classes + + +