Commit db2f4b70 authored by Tino Goratsch's avatar Tino Goratsch

Merge branch 'release/composer-suggest'

parents 9751dfd2 3fa8a520
......@@ -45,11 +45,13 @@ deploy:
condition: "$TRAVIS_PHP_VERSION = '7.0'"
- provider: script
script: ./build/travis/update_module_repositories.sh ${TRAVIS_TAG}
skip_cleanup: true
on:
tags: true
condition: "$TRAVIS_PHP_VERSION = '7.0'"
- provider: script
script: ./build/travis/update_version_check.sh ${TRAVIS_TAG}
skip_cleanup: true
on:
tags: true
condition: "$TRAVIS_PHP_VERSION = '7.0'"
......
......@@ -92,11 +92,14 @@ class ServiceContainerBuilder extends ContainerBuilder
foreach ($availableModules as $module) {
foreach ($vendors as $vendor) {
$path = $this->applicationPath->getModulesDir() . $vendor . '/' . $module['dir'] . '/Resources/config/services.yml';
$modulePath = $this->applicationPath->getModulesDir() . $vendor . '/' . $module['dir'];
$path = $modulePath . '/Resources/config/services.yml';
if (is_file($path)) {
$loader->load($path);
}
$this->registerCompilerPass($vendor, $module['dir']);
}
}
......@@ -118,4 +121,21 @@ class ServiceContainerBuilder extends ContainerBuilder
) {
return new static($applicationPath, $symfonyRequest, $applicationMode, $allModules);
}
/**
* @param string $vendor
* @param string $moduleName
*/
private function registerCompilerPass($vendor, $moduleName)
{
$fqn = "\\ACP3\\Modules\\" . $vendor . "\\" . $moduleName . "\\ModuleRegistration";
if (class_exists($fqn)) {
$instance = new $fqn;
if ($instance instanceof Modules\ModuleRegistration) {
$instance->build($this);
}
}
}
}
<?php
/**
* Copyright (c) 2016 by the ACP3 Developers.
* See the LICENCE file at the top-level module directory for licencing details.
*/
namespace ACP3\Core\Modules;
use Symfony\Component\DependencyInjection\ContainerBuilder;
class ModuleRegistration
{
/**
* @param ContainerBuilder $containerBuilder
*/
public function build(ContainerBuilder $containerBuilder)
{
}
}
<?php
/**
* Copyright (c) 2016 by the ACP3 Developers.
* See the LICENCE file at the top-level module directory for licencing details.
*/
namespace ACP3\Core\Test\View\Renderer\Smarty\Modifiers;
use ACP3\Core\View\Renderer\Smarty\Modifiers\PrefixUri;
class PrefixUriTest extends \PHPUnit_Framework_TestCase
{
/**
* @var PrefixUri
*/
private $prefixUri;
protected function setUp()
{
$this->prefixUri = new PrefixUri();
}
public function testAddUriPrefix()
{
$value = 'www.example.com';
$expected = 'http://www.example.com';
$this->assertEquals($expected, $this->prefixUri->process($value));
}
public function testAddUriPrefixNotNeeded()
{
$value = 'http://www.example.com';
$expected = 'http://www.example.com';
$this->assertEquals($expected, $this->prefixUri->process($value));
}
}
......@@ -29,6 +29,6 @@ class PrefixUri extends AbstractModifier
return 'http://' . $value;
}
return '';
return $value;
}
}
<?php
/**
* Copyright (c) 2016 by the ACP3 Developers.
* See the LICENCE file at the top-level module directory for licencing details.
*/
namespace ACP3\Modules\ACP3\Articles\Event\Listener;
use ACP3\Modules\ACP3\Search\Event\AvailableModulesEvent;
/**
* Class OnAvailableModulesListener
* @package ACP3\Modules\ACP3\Articles\Event\Listener
*/
class OnAvailableModulesListener
{
/**
* @param \ACP3\Modules\ACP3\Search\Event\AvailableModulesEvent $availableModules
*/
public function onAvailableModules(AvailableModulesEvent $availableModules)
{
$availableModules->addAvailableModule('articles');
}
}
......@@ -9,22 +9,6 @@ services:
tags:
- { name: core.eventListener, event: articles.model.articles.after_delete, method: execute }
articles.events.on_available_modules_listener:
class: ACP3\Modules\ACP3\Articles\Event\Listener\OnAvailableModulesListener
tags:
- { name: core.eventListener, event: search.events.availableModules, method: onAvailableModules }
articles.events.on_display_search_results_listener:
class: ACP3\Modules\ACP3\Articles\Event\Listener\OnDisplaySearchResultsListener
arguments:
- '@core.acl'
- '@core.date'
- '@core.lang'
- '@core.router'
- '@articles.model.articlerepository'
tags:
- { name: core.eventListener, event: search.events.displaySearchResults, method: onDisplaySearchResults }
articles.events.update_article_cache_on_model_save_after_listener:
class: ACP3\Modules\ACP3\Articles\Event\Listener\UpdateArticleCacheOnModelSaveAfterListener
arguments:
......
services:
articles.search.search_availability:
class: ACP3\Modules\ACP3\Articles\Search\SearchAvailability
arguments:
- '@core.date'
- '@core.router'
- '@articles.model.articlerepository'
tags:
- { name: search.available_module }
......@@ -4,6 +4,7 @@ imports:
- { resource: components/events.yml }
- { resource: components/installer.yml }
- { resource: components/models.yml }
- { resource: components/search.yml }
- { resource: components/validation.yml }
services:
......
......@@ -4,33 +4,21 @@
* See the LICENCE file at the top-level module directory for licencing details.
*/
namespace ACP3\Modules\ACP3\Articles\Event\Listener;
namespace ACP3\Modules\ACP3\Articles\Search;
use ACP3\Core\ACL;
use ACP3\Core\Date;
use ACP3\Core\I18n\Translator;
use ACP3\Core\Router\RouterInterface;
use ACP3\Modules\ACP3\Articles\Installer\Schema;
use ACP3\Modules\ACP3\Articles\Model\Repository\ArticleRepository;
use ACP3\Modules\ACP3\Search\Event\SearchResultsEvent;
use ACP3\Modules\ACP3\Search\Utility\SearchAvailabilityInterface;
/**
* Class OnDisplaySearchResultsListener
* @package ACP3\Modules\ACP3\Articles\Event\Listener
*/
class OnDisplaySearchResultsListener
class SearchAvailability implements SearchAvailabilityInterface
{
/**
* @var \ACP3\Core\ACL
*/
private $acl;
/**
* @var \ACP3\Core\Date
*/
private $date;
/**
* @var \ACP3\Core\I18n\Translator
*/
private $translator;
/**
* @var \ACP3\Core\Router\RouterInterface
*/
......@@ -41,62 +29,52 @@ class OnDisplaySearchResultsListener
private $articleRepository;
/**
* OnDisplaySearchResultsListener constructor.
*
* @param \ACP3\Core\ACL $acl
* @param \ACP3\Core\Date $date
* @param \ACP3\Core\I18n\Translator $translator
* @param \ACP3\Core\Router\RouterInterface $router
* @param \ACP3\Modules\ACP3\Articles\Model\Repository\ArticleRepository $articleRepository
* SearchAvailability constructor.
* @param Date $date
* @param RouterInterface $router
* @param ArticleRepository $articleRepository
*/
public function __construct(
ACL $acl,
Date $date,
Translator $translator,
RouterInterface $router,
ArticleRepository $articleRepository
) {
$this->acl = $acl;
$this->date = $date;
$this->translator = $translator;
$this->router = $router;
$this->articleRepository = $articleRepository;
}
/**
* @param \ACP3\Modules\ACP3\Search\Event\SearchResultsEvent $displaySearchResults
* @return string
*/
public function onDisplaySearchResults(SearchResultsEvent $displaySearchResults)
public function getModuleName()
{
if (in_array('articles', $displaySearchResults->getModules())
&& $this->acl->hasPermission('frontend/articles') === true
) {
$fields = $this->mapSearchAreasToFields($displaySearchResults->getAreas());
return Schema::MODULE_NAME;
}
$results = $this->articleRepository->getAllSearchResults(
$fields,
$displaySearchResults->getSearchTerm(),
$displaySearchResults->getSortDirection(),
$this->date->getCurrentDateTime()
);
$cResults = count($results);
/**
* @param string $searchTerm
* @param string $areas
* @param string $sortDirection
* @return array
*/
public function fetchSearchResults($searchTerm, $areas, $sortDirection)
{
$fields = $this->mapSearchAreasToFields($areas);
if ($cResults > 0) {
$searchResults = [];
$searchResults['dir'] = 'articles';
for ($i = 0; $i < $cResults; ++$i) {
$searchResults['results'][$i] = $results[$i];
$searchResults['results'][$i]['hyperlink'] = $this->router->route(
'articles/index/details/id_' . $results[$i]['id']
);
}
$results = $this->articleRepository->getAllSearchResults(
$fields,
$searchTerm,
$sortDirection,
$this->date->getCurrentDateTime()
);
$cResults = count($results);
$displaySearchResults->addSearchResultsByModule(
$this->translator->t('articles', 'articles'),
$searchResults
);
}
for ($i = 0; $i < $cResults; ++$i) {
$results[$i]['hyperlink'] = $this->router->route('articles/index/details/id_' . $results[$i]['id']);
}
return $results;
}
/**
......
......@@ -21,10 +21,12 @@
"acp3/setup": "^4.1.30",
"acp3/module-errors": "^4.1.30",
"acp3/module-permissions": "^4.1.30",
"acp3/module-seo": "^4.1.30",
"acp3/module-system": "^4.1.30",
"acp3/module-users": "^4.1.30"
},
"suggest": {
"acp3/module-seo": "Provides additional SEO capabilities"
},
"autoload": {
"psr-4": {
"ACP3\\Modules\\ACP3\\Articles\\": ""
......
<?php
/**
* Copyright (c) 2016 by the ACP3 Developers.
* See the LICENCE file at the top-level module directory for licencing details.
*/
namespace ACP3\Modules\ACP3\Captcha\Event\Listener;
use ACP3\Core\I18n\Translator;
use ACP3\Core\Validation\Event\FormValidationEvent;
use ACP3\Modules\ACP3\Captcha\Validation\ValidationRules\CaptchaValidationRule;
class OnCaptchaValidationValidateCaptchaListener
{
/**
* @var Translator
*/
private $translator;
/**
* OnCaptchaValidationValidateCaptcha constructor.
* @param Translator $translator
*/
public function __construct(Translator $translator)
{
$this->translator = $translator;
}
/**
* @param FormValidationEvent $event
*/
public function validateCaptcha(FormValidationEvent $event)
{
$event
->getValidator()
->addConstraint(
CaptchaValidationRule::class,
[
'data' => $event->getFormData(),
'field' => 'captcha',
'message' => $this->translator->t('captcha', 'invalid_captcha_entered')
]
);
}
}
......@@ -5,4 +5,11 @@ services:
- '@core.acl'
- '@captcha.helpers'
tags:
- { name: core.eventListener, event: captcha.event.display_captcha, method: onDisplayCaptcha }
\ No newline at end of file
- { name: core.eventListener, event: captcha.event.display_captcha, method: onDisplayCaptcha }
captcha.event.on_captcha_validation_validate_captcha_listener:
class: ACP3\Modules\ACP3\Captcha\Event\Listener\OnCaptchaValidationValidateCaptchaListener
arguments:
- '@core.lang'
tags:
- { name: core.eventListener, event: captcha.validation.validate_captcha, method: validateCaptcha }
......@@ -81,11 +81,16 @@ class CaptchaValidationRule extends AbstractValidationRule
return true;
}
protected function checkCaptcha($input, $path)
/**
* @param string $value
* @param string $path
* @return bool
*/
protected function checkCaptcha($value, $path)
{
$index = 'captcha_' . sha1($this->router->route(empty($path) === true ? $this->request->getQuery() : $path));
$indexName = 'captcha_' . sha1($this->router->route(empty($path) === true ? $this->request->getQuery() : $path));
return preg_match('/^[a-zA-Z0-9]+$/', $input)
&& strtolower($input) === strtolower($this->sessionHandler->get($index, ''));
return preg_match('/^[a-zA-Z0-9]+$/', $value)
&& strtolower($value) === strtolower($this->sessionHandler->get($indexName, ''));
}
}
......@@ -2,7 +2,6 @@
namespace ACP3\Modules\ACP3\Comments\Validation;
use ACP3\Core;
use ACP3\Modules\ACP3\Captcha\Validation\ValidationRules\CaptchaValidationRule;
use ACP3\Modules\ACP3\Comments\Validation\ValidationRules\FloodBarrierValidationRule;
/**
......@@ -53,15 +52,9 @@ class FormValidation extends Core\Validation\AbstractFormValidation
'data' => $formData,
'field' => 'message',
'message' => $this->translator->t('system', 'message_to_short')
])
->addConstraint(
CaptchaValidationRule::class,
[
'data' => $formData,
'field' => 'captcha',
'message' => $this->translator->t('captcha', 'invalid_captcha_entered')
]
);
]);
$this->validator->dispatchValidationEvent('captcha.validation.validate_captcha', $formData);
$this->validator->validate();
}
......
......@@ -24,6 +24,9 @@
"acp3/module-system": "^4.1.30",
"acp3/module-users": "^4.1.30"
},
"suggest": {
"acp3/module-captcha": "Provides basic protection against spam bots."
},
"autoload": {
"psr-4": {
"ACP3\\Modules\\ACP3\\Comments\\": ""
......
......@@ -70,10 +70,10 @@ class ContactFormModel
*/
protected function sendEmail(array $formData)
{
$seoSettings = $this->getSeoSettings();
$systemSettings = $this->getSystemSettings();
$settings = $this->getContactSettings();
$subject = $this->buildSubject('contact_subject', $seoSettings['title']);
$subject = $this->buildSubject('contact_subject', $systemSettings['site_title']);
$body = $this->buildEmailBody($formData, 'contact_body');
return $this->sendEmail->execute(
......@@ -88,9 +88,9 @@ class ContactFormModel
/**
* @return array
*/
protected function getSeoSettings()
protected function getSystemSettings()
{
return $this->config->getSettings(\ACP3\Modules\ACP3\Seo\Installer\Schema::MODULE_NAME);
return $this->config->getSettings(\ACP3\Modules\ACP3\System\Installer\Schema::MODULE_NAME);
}
/**
......@@ -135,10 +135,10 @@ class ContactFormModel
*/
protected function sendEmailCopy(array $formData)
{
$seoSettings = $this->getSeoSettings();
$systemSettings = $this->getSystemSettings();
$settings = $this->getContactSettings();
$subject = $this->buildSubject('sender_subject', $seoSettings['title']);
$subject = $this->buildSubject('sender_subject', $systemSettings['site_title']);
$body = $this->buildEmailBody($formData, 'sender_body');
return $this->sendEmail->execute(
......
......@@ -3,7 +3,6 @@
namespace ACP3\Modules\ACP3\Contact\Validation;
use ACP3\Core;
use ACP3\Modules\ACP3\Captcha\Validation\ValidationRules\CaptchaValidationRule;
/**
* Class FormValidation
......@@ -38,15 +37,10 @@ class FormValidation extends Core\Validation\AbstractFormValidation
'data' => $formData,
'field' => 'message',
'message' => $this->translator->t('system', 'message_to_short')
])
->addConstraint(
CaptchaValidationRule::class,
[
'data' => $formData,
'field' => 'captcha',
'message' => $this->translator->t('captcha', 'invalid_captcha_entered')
]);
$this->validator->dispatchValidationEvent('captcha.validation.validate_captcha', $formData);
$this->validator->validate();
}
}
......@@ -21,10 +21,12 @@
"acp3/setup": "^4.1.30",
"acp3/module-errors": "^4.1.30",
"acp3/module-permissions": "^4.1.30",
"acp3/module-seo": "^4.1.30",
"acp3/module-system": "^4.1.30",
"acp3/module-users": "^4.1.30"
},
"suggest": {
"acp3/module-captcha": "Provides basic protection against spam bots."
},
"autoload": {
"psr-4": {
"ACP3\\Modules\\ACP3\\Contact\\": ""
......
......@@ -20,7 +20,6 @@
"acp3/core": "^4.1.30",
"acp3/setup": "^4.1.30",
"acp3/module-permissions": "^4.1.30",
"acp3/module-seo": "^4.1.30",
"acp3/module-system": "^4.1.30",
"acp3/module-users": "^4.1.30"
},
......
......@@ -8,7 +8,7 @@ namespace ACP3\Modules\ACP3\Feeds\Controller\Frontend\Index;
use ACP3\Core;
use ACP3\Modules\ACP3\Feeds;
use ACP3\Modules\ACP3\Seo\Installer\Schema;
use ACP3\Modules\ACP3\System\Installer\Schema;
/**
* Class Index
......@@ -19,21 +19,28 @@ class Index extends Core\Controller\AbstractFrontendAction
use Core\Cache\CacheResponseTrait;
/**
* @var \ACP3\Modules\ACP3\Feeds\Helper\FeedGenerator
* @var \ACP3\Modules\ACP3\Feeds\View\Renderer\FeedGenerator
*/
protected $feedGenerator;
/**
* @var Feeds\Utility\AvailableFeedsRegistrar
*/
protected $availableFeedsRegistrar;
/**
* @param \ACP3\Core\Controller\Context\FrontendContext $context
* @param \ACP3\Modules\ACP3\Feeds\Helper\FeedGenerator $feedGenerator
* @param \ACP3\Modules\ACP3\Feeds\View\Renderer\FeedGenerator $feedGenerator
* @param Feeds\Utility\AvailableFeedsRegistrar $availableFeedsRegistrar
*/
public function __construct(
Core\Controller\Context\FrontendContext $context,
Feeds\Helper\FeedGenerator $feedGenerator)
{
Feeds\View\Renderer\FeedGenerator $feedGenerator,
Feeds\Utility\AvailableFeedsRegistrar $availableFeedsRegistrar
) {
parent::__construct($context);
$this->feedGenerator = $feedGenerator;
$this->availableFeedsRegistrar = $availableFeedsRegistrar;
}
/**
......@@ -46,20 +53,24 @@ class Index extends Core\Controller\AbstractFrontendAction
{
if ($this->acl->hasPermission('frontend/' . $feed) === true) {
$this->setCacheResponseCacheable(
$this->config->getSettings(\ACP3\Modules\ACP3\System\Installer\Schema::MODULE_NAME)['cache_lifetime']
$this->config->getSettings(Schema::MODULE_NAME)['cache_lifetime']
);
$this->feedGenerator
->setTitle($this->config->getSettings(Schema::MODULE_NAME)['title'])
->setDescription($this->translator->t($feed, $feed));
try {
$feedItems = $this->availableFeedsRegistrar
->getFeedItemsByModuleName($feed)
->fetchFeedItems();
$this->eventDispatcher->dispatch(
'feeds.events.displayFeed.' . strtolower($feed),
new Feeds\Event\DisplayFeed($this->feedGenerator)
);
$this->feedGenerator
->setTitle($this->config->getSettings(Schema::MODULE_NAME)['site_title'])
->setDescription($this->translator->t($feed, $feed))
->assign($feedItems);
$this->setContentType('text/xml');
return $this->response->setContent($this->feedGenerator->generateFeed());
} catch (\InvalidArgumentException $e) {
$this->setContentType('text/xml');
return $this->response->setContent($this->feedGenerator->generateFeed());
}
}
throw new Core\Controller\Exception\ResultNotExistsException();
......
<?php
/**
* Copyright (c) 2016 by the ACP3 Developers.
* See the LICENCE file at the top-level module directory for licencing details.
*/
namespace ACP3\Modules\ACP3\Feeds\DependencyInjection;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Reference;
class FeedAvailabilityCompilerPass implements CompilerPassInterface
{
/**
* You can modify the container here before it is dumped to PHP code.
*
* @param ContainerBuilder $container
*/
public function process(ContainerBuilder $container)
{
$definition = $container->findDefinition('feeds.utility.available_feeds_registrar');
$plugins = $container->findTaggedServiceIds('feeds.available_module');
foreach ($plugins as $serviceId => $tags) {
$definition->addMethodCall(
'registerModule',
[new Reference($serviceId)]
);
}
}
}