diff --git a/CHANGELOG.md b/CHANGELOG.md index 68fba472..217fb63e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,13 @@ +# Version 18.1.0 + +## Features + +### PHP 8.4 Compatibility + +* Update dependencies +* Add PHP 8.4 support +* Replace abandoned `swiftmailer/swiftmailer` with `symfony/mailer` + # Version 18.0.0 ### PHP 8.1 Compatibility diff --git a/composer.json b/composer.json index 9d835feb..74cb455b 100755 --- a/composer.json +++ b/composer.json @@ -4,22 +4,22 @@ "license": "MIT", "require": { "php": "^8.1", - "psr/log": "^1.0.0|^2.0.0|^3.0.0", - "psr/cache" : "^2.0.0|^3.0.0", + "psr/log": "^1.0|^2.0|^3.0", + "psr/cache" : "^2.0|^3.0", "psr/container": "^1.1.2", - "handcraftedinthealps/goodby-csv": "^1.4.2", + "handcraftedinthealps/goodby-csv": "^1.4", "monolog/monolog": "^2.9|^3.7", - "league/event": "^2.2.0", + "league/event": "^2.2", "ramsey/uuid": "^4.2|^4.7", - "swiftmailer/swiftmailer": "v6.3.0", - "laminas/laminas-filter": "^2.31.0", - "techdivision/import-dbal": "^2.0.0", - "techdivision/import-dbal-collection": "^2.0.0", - "techdivision/import-cache": "^2.0.0", - "techdivision/import-cache-collection": "^2.0.0", - "techdivision/import-serializer": "^2.0.0", - "techdivision/import-serializer-csv": "^2.0.0", - "techdivision/import-configuration": "^6.0.0.", + "symfony/mailer": "^5.4|^6.4", + "laminas/laminas-filter": "^2.31", + "techdivision/import-dbal": "^2.0", + "techdivision/import-dbal-collection": "^2.1", + "techdivision/import-cache": "^2.0", + "techdivision/import-cache-collection": "^2.0", + "techdivision/import-serializer": "^2.1", + "techdivision/import-serializer-csv": "^2.1", + "techdivision/import-configuration": "^6.1", "ext-json": "*", "ext-zip": "*" }, diff --git a/src/Adapter/Goodby/Lexer.php b/src/Adapter/Goodby/Lexer.php index f5a70a5b..4a2e4ae0 100644 --- a/src/Adapter/Goodby/Lexer.php +++ b/src/Adapter/Goodby/Lexer.php @@ -43,7 +43,7 @@ class Lexer implements LexerInterface * * @param \Goodby\CSV\Import\Standard\LexerConfig $config The lexer configuration */ - public function __construct(LexerConfig $config = null) + public function __construct(?LexerConfig $config = null) { // query whether or not a configuration has been passed diff --git a/src/Adapter/SerializerAwareAdapterInterface.php b/src/Adapter/SerializerAwareAdapterInterface.php index b76291a7..fdc86ab6 100644 --- a/src/Adapter/SerializerAwareAdapterInterface.php +++ b/src/Adapter/SerializerAwareAdapterInterface.php @@ -48,7 +48,7 @@ public function explode($value = null, $delimiter = null); * * @return string|null The compatected value */ - public function implode(array $value = null, $delimiter = null); + public function implode(?array $value = null, $delimiter = null); /** * Serializes the elements of the passed array. @@ -57,7 +57,7 @@ public function implode(array $value = null, $delimiter = null); * * @return string The serialized array */ - public function serialize(array $unserialized = null); + public function serialize(?array $unserialized = null); /** * Unserializes the elements of the passed string. diff --git a/src/Adapter/SerializerTrait.php b/src/Adapter/SerializerTrait.php index 4aec6f9c..d34dd888 100644 --- a/src/Adapter/SerializerTrait.php +++ b/src/Adapter/SerializerTrait.php @@ -80,7 +80,7 @@ public function explode($value = null, $delimiter = null) * * @return string|null The compatected value */ - public function implode(array $value = null, $delimiter = null) + public function implode(?array $value = null, $delimiter = null) { return $this->getSerializer()->implode($value, $delimiter); } @@ -93,7 +93,7 @@ public function implode(array $value = null, $delimiter = null) * * @return string The serialized array */ - public function serialize(array $unserialized = null, $delimiter = null) + public function serialize(?array $unserialized = null, $delimiter = null) { return $this->getSerializer()->serialize($unserialized, $delimiter); } diff --git a/src/Callbacks/AbstractBooleanCallback.php b/src/Callbacks/AbstractBooleanCallback.php index 9abe16a9..54817fce 100644 --- a/src/Callbacks/AbstractBooleanCallback.php +++ b/src/Callbacks/AbstractBooleanCallback.php @@ -50,7 +50,7 @@ abstract class AbstractBooleanCallback extends AbstractCallback * * @return mixed The modified value */ - public function handle(AttributeCodeAndValueAwareObserverInterface $observer = null) + public function handle(?AttributeCodeAndValueAwareObserverInterface $observer = null) { // set the observer @@ -100,7 +100,7 @@ public function handle(AttributeCodeAndValueAwareObserverInterface $observer = n // return NULL, if NO value can be mapped to a boolean representation return; } - + // throw an exception if the attribute is not available throw new \Exception( $this->appendExceptionSuffix( diff --git a/src/Callbacks/AbstractCallback.php b/src/Callbacks/AbstractCallback.php index 0554801f..77688caf 100644 --- a/src/Callbacks/AbstractCallback.php +++ b/src/Callbacks/AbstractCallback.php @@ -14,6 +14,7 @@ namespace TechDivision\Import\Callbacks; +use Exception; use TechDivision\Import\Observers\ObserverInterface; /** @@ -108,14 +109,14 @@ protected function appendExceptionSuffix($message = null, $filename = null, $lin * line number and column name and use it for a detailed exception message. * * @param string $columnName The column name that should be resolved - * @param \Exception $parent The exception we want to wrap + * @param Exception|null $parent The exception we want to wrap * @param string $className The class name of the exception type we want to wrap the parent one * - * @return \Exception the wrapped exception + * @return Exception the wrapped exception */ protected function wrapException( $columnName, - \Exception $parent = null, + ?Exception $parent = null, $className = '\TechDivision\Import\Exceptions\WrappedColumnException' ) { return $this->getSubject()->wrapException($columnName, $parent, $className); @@ -130,7 +131,7 @@ protected function isDebugMode() { return $this->getSubject()->isDebugMode(); } - + /** * Queries whether or not strict mode is enabled or not, default is True. * Backward compatibility @@ -181,7 +182,7 @@ protected function mergeAttributesRecursive(array $status) * * @return mixed|null The, almost formatted, value */ - protected function getValue($name, $default = null, callable $callback = null) + protected function getValue($name, $default = null, ?callable $callback = null) { return $this->getSubject()->getValue($name, $default, $callback); } @@ -192,7 +193,7 @@ protected function getValue($name, $default = null, callable $callback = null) * @param string $storeViewCode The store view code to return the store ID for * * @return integer The ID of the store with the passed ID - * @throws \Exception Is thrown, if the store with the actual code is not available + * @throws Exception Is thrown, if the store with the actual code is not available */ protected function getStoreId($storeViewCode) { @@ -206,7 +207,7 @@ protected function getStoreId($storeViewCode) * @param string|null $default The default store view code to use, if no store view code is set in the CSV file * * @return integer The ID of the actual store - * @throws \Exception Is thrown, if the store with the actual code is not available + * @throws Exception Is thrown, if the store with the actual code is not available */ protected function getRowStoreId($default = null) { diff --git a/src/Callbacks/AbstractMultiselectCallback.php b/src/Callbacks/AbstractMultiselectCallback.php index 7bec91a8..dd54ecf3 100644 --- a/src/Callbacks/AbstractMultiselectCallback.php +++ b/src/Callbacks/AbstractMultiselectCallback.php @@ -38,7 +38,7 @@ abstract class AbstractMultiselectCallback extends AbstractEavAwareCallback * * @return mixed The modified value */ - public function handle(AttributeCodeAndValueAwareObserverInterface $observer = null) + public function handle(?AttributeCodeAndValueAwareObserverInterface $observer = null) { // set the observer diff --git a/src/Callbacks/AbstractSelectCallback.php b/src/Callbacks/AbstractSelectCallback.php index e8c81adf..76fc1605 100644 --- a/src/Callbacks/AbstractSelectCallback.php +++ b/src/Callbacks/AbstractSelectCallback.php @@ -38,7 +38,7 @@ abstract class AbstractSelectCallback extends AbstractEavAwareCallback * * @return mixed The modified value */ - public function handle(AttributeCodeAndValueAwareObserverInterface $observer = null) + public function handle(?AttributeCodeAndValueAwareObserverInterface $observer = null) { // set the observer @@ -100,7 +100,7 @@ public function handle(AttributeCodeAndValueAwareObserverInterface $observer = n // return NULL, if the value can't be mapped to an option return; } - + // throw an exception if the attribute is NOT // available and we're in strict mode throw new \Exception( diff --git a/src/Exceptions/InvalidDataException.php b/src/Exceptions/InvalidDataException.php index 3a7bf443..de858170 100644 --- a/src/Exceptions/InvalidDataException.php +++ b/src/Exceptions/InvalidDataException.php @@ -34,9 +34,9 @@ class InvalidDataException extends \Exception * * @param string $message [optional] The Exception message to throw. * @param int $code [optional] The Exception code. - * @param null|Throwable $previous [optional] The previous throwable used for the exception chaining. + * @param Throwable|null $previous [optional] The previous throwable used for the exception chaining. */ - public function __construct($message = "", $code = self::INVALID_DATA_CODE, Throwable $previous = null) + public function __construct($message = "", $code = self::INVALID_DATA_CODE, ?Throwable $previous = null) { parent::__construct($message, $code, $previous); } diff --git a/src/Exceptions/MissingFileException.php b/src/Exceptions/MissingFileException.php index 4798a1e5..acc12070 100644 --- a/src/Exceptions/MissingFileException.php +++ b/src/Exceptions/MissingFileException.php @@ -36,7 +36,7 @@ class MissingFileException extends \Exception * @param int $code [optional] The Exception code. * @param null|Throwable $previous [optional] The previous throwable used for the exception chaining. */ - public function __construct($message = "", $code = self::NOT_FOUND_CODE, Throwable $previous = null) + public function __construct($message = "", $code = self::NOT_FOUND_CODE, ?Throwable $previous = null) { parent::__construct($message, $code, $previous); } diff --git a/src/Execution/ConfigurationManager.php b/src/Execution/ConfigurationManager.php index 7cf75694..1342db47 100644 --- a/src/Execution/ConfigurationManager.php +++ b/src/Execution/ConfigurationManager.php @@ -105,12 +105,15 @@ public function getOperations() if ($shortcut = $configuration->getShortcut()) { // load the entity type code and map it to the Magento edition $magentoEdition = $this->mapEntityTypeToMagentoEdition($entityTypeCode); - // load the operation names from the shorcuts - foreach ($shortcuts[$magentoEdition][$entityTypeCode] as $shortcutName => $opNames) { - // query whether or not the operation has to be executed or not - if ($shortcutName === $shortcut) { - foreach ($opNames as $opName) { - $configuration->addOperationName($opName); + // load the operation names from the shortcuts if available + if (isset($shortcuts[$magentoEdition], $shortcuts[$magentoEdition][$entityTypeCode]) + && is_array($shortcuts[$magentoEdition][$entityTypeCode])) { + foreach ($shortcuts[$magentoEdition][$entityTypeCode] as $shortcutName => $opNames) { + // query whether or not the operation has to be executed or not + if ($shortcutName === $shortcut) { + foreach ($opNames as $opName) { + $configuration->addOperationName($opName); + } } } } diff --git a/src/Handlers/OkFileHandler.php b/src/Handlers/OkFileHandler.php index 5080f765..12bc1b7d 100644 --- a/src/Handlers/OkFileHandler.php +++ b/src/Handlers/OkFileHandler.php @@ -57,7 +57,7 @@ class OkFileHandler implements OkFileHandlerInterface * * @param \TechDivision\Import\Handlers\GenericFileHandlerInterface|null $genericFileHandler The generic file handler instance */ - public function __construct(GenericFileHandlerInterface $genericFileHandler = null) + public function __construct(?GenericFileHandlerInterface $genericFileHandler = null) { $this->genericFileHandler = $genericFileHandler ?? new GenericFileHandler(); } diff --git a/src/Handlers/OkFileHandlerFactory.php b/src/Handlers/OkFileHandlerFactory.php index 95cf42a3..26cec7e1 100644 --- a/src/Handlers/OkFileHandlerFactory.php +++ b/src/Handlers/OkFileHandlerFactory.php @@ -86,7 +86,7 @@ protected function getLoaderFactory() : LoaderFactoryInterface * * @return \TechDivision\Import\Handlers\HandlerInterface|null The new handler instance */ - public function createHandler(SubjectConfigurationInterface $subject = null) : HandlerInterface + public function createHandler(?SubjectConfigurationInterface $subject = null) : HandlerInterface { // load the proposed .OK file loader diff --git a/src/Handlers/PidFileHandler.php b/src/Handlers/PidFileHandler.php index 880087e7..79183ff8 100644 --- a/src/Handlers/PidFileHandler.php +++ b/src/Handlers/PidFileHandler.php @@ -68,12 +68,12 @@ class PidFileHandler implements PidFileHandlerInterface * * @param \TechDivision\Import\Configuration\ConfigurationInterface $configuration The actual configuration instance * @param \TechDivision\Import\Handlers\GenericFileHandlerInterface $genericFileHandler The actual file handler instance - * @param \Doctrine\Common\Collections\Collection $systemLoggers The array with the system logger instances + * @param \Doctrine\Common\Collections\Collection|null $systemLoggers The array with the system logger instances */ public function __construct( ConfigurationInterface $configuration, GenericFileHandlerInterface $genericFileHandler, - Collection $systemLoggers = null + ?Collection $systemLoggers = null ) { $this->configuration = $configuration; $this->genericFileHandler = $genericFileHandler; diff --git a/src/Interfaces/PregMatchAwareInterface.php b/src/Interfaces/PregMatchAwareInterface.php index a64f7cd0..7bdd02b9 100644 --- a/src/Interfaces/PregMatchAwareInterface.php +++ b/src/Interfaces/PregMatchAwareInterface.php @@ -65,7 +65,7 @@ public function addMatches(array $matches) : void; * * @return bool TRUE if the match with the passed name and key is available, else FALSE */ - public function hasMatch(string $name, string $key = null) : bool; + public function hasMatch(string $name, ?string $key = null) : bool; /** * Return's the value of the key with the passed name out of the matches @@ -77,5 +77,5 @@ public function hasMatch(string $name, string $key = null) : bool; * @return string The match itself * @throws \InvalidArgumentException Is thrown the value of the match with the passed name and key is not available */ - public function getMatch(string $name, string $key = null) : string; + public function getMatch(string $name, ?string $key = null) : string; } diff --git a/src/Listeners/ArchiveListener.php b/src/Listeners/ArchiveListener.php index c9d1f22e..9e04b3a1 100644 --- a/src/Listeners/ArchiveListener.php +++ b/src/Listeners/ArchiveListener.php @@ -124,7 +124,7 @@ protected function getConfiguration() * * @return void */ - public function handle(EventInterface $event, ApplicationInterface $application = null) + public function handle(EventInterface $event, ?ApplicationInterface $application = null) { // query whether or not, the import artefacts have to be archived diff --git a/src/Listeners/CacheUrlRewriteListener.php b/src/Listeners/CacheUrlRewriteListener.php index 622cc200..a96a0f20 100644 --- a/src/Listeners/CacheUrlRewriteListener.php +++ b/src/Listeners/CacheUrlRewriteListener.php @@ -86,12 +86,12 @@ public function getKey() * Handle the event. * * @param \League\Event\EventInterface $event The event that triggered the listener - * @param \TechDivision\Import\Dbal\Actions\CachedActionInterface $action The action instance that triggered the event + * @param \TechDivision\Import\Dbal\Actions\CachedActionInterface|null $action The action instance that triggered the event * @param array $row The row to be cached * * @return void */ - public function handle(EventInterface $event, CachedActionInterface $action = null, array $row = array()) + public function handle(EventInterface $event, ?CachedActionInterface $action = null, array $row = array()) { // prepare the unique cache key for the EAV attribute option value diff --git a/src/Listeners/ClearDirectoriesListener.php b/src/Listeners/ClearDirectoriesListener.php index c1defc34..feb51de9 100644 --- a/src/Listeners/ClearDirectoriesListener.php +++ b/src/Listeners/ClearDirectoriesListener.php @@ -68,7 +68,7 @@ public function __construct( * * @return void */ - public function handle(EventInterface $event, ApplicationInterface $application = null) + public function handle(EventInterface $event, ?ApplicationInterface $application = null) { // clear the filecache diff --git a/src/Listeners/ImportHistoryListener.php b/src/Listeners/ImportHistoryListener.php index b1a5a8e4..ddb88867 100644 --- a/src/Listeners/ImportHistoryListener.php +++ b/src/Listeners/ImportHistoryListener.php @@ -167,7 +167,7 @@ protected function loadAdminUserByUsername($username) * * @return void */ - public function handle(EventInterface $event, ApplicationInterface $application = null) + public function handle(EventInterface $event, ?ApplicationInterface $application = null) { // load the registry processor diff --git a/src/Listeners/InvalidDataListener.php b/src/Listeners/InvalidDataListener.php index 2a5ba229..821acc07 100644 --- a/src/Listeners/InvalidDataListener.php +++ b/src/Listeners/InvalidDataListener.php @@ -52,9 +52,8 @@ public function __construct(RegistryProcessorInterface $registryProcessor) * @param ApplicationInterface|null $application The application instance * * @return void - * @throws \TechDivision\Import\Exceptions\MissingFileException */ - public function handle(EventInterface $event, ApplicationInterface $application = null) + public function handle(EventInterface $event, ?ApplicationInterface $application = null) { // load the validations from the registry $noStrictValidations = $this->getRegistryProcessor()->getAttribute(RegistryKeys::NO_STRICT_VALIDATIONS); diff --git a/src/Listeners/MissingFilesListener.php b/src/Listeners/MissingFilesListener.php index 9370faa5..0a2d62b2 100644 --- a/src/Listeners/MissingFilesListener.php +++ b/src/Listeners/MissingFilesListener.php @@ -60,7 +60,7 @@ public function __construct(RegistryProcessorInterface $registryProcessor, $noFi * @return void * @throws \TechDivision\Import\Exceptions\MissingFileException */ - public function handle(EventInterface $event, ApplicationInterface $application = null) + public function handle(EventInterface $event, ?ApplicationInterface $application = null) { // load the validations from the registry diff --git a/src/Listeners/PrepareDebugDumpListener.php b/src/Listeners/PrepareDebugDumpListener.php index c443667c..b867b06f 100644 --- a/src/Listeners/PrepareDebugDumpListener.php +++ b/src/Listeners/PrepareDebugDumpListener.php @@ -86,11 +86,11 @@ private function getConfiguration() : ConfigurationInterface * Handle the event. * * @param \League\Event\EventInterface $event The event that triggered the listener - * @param \TechDivision\Import\ApplicationInterface $application The application instance + * @param \TechDivision\Import\ApplicationInterface|null $application The application instance * * @return void */ - public function handle(EventInterface $event, ApplicationInterface $application = null) + public function handle(EventInterface $event, ?ApplicationInterface $application = null) { if ($this->getConfiguration()->isDebugMode()) { $this->getDebugUtil()->prepareDump($application->getSerial()); diff --git a/src/Listeners/RenderAnsiArtListener.php b/src/Listeners/RenderAnsiArtListener.php index 1918d0b1..835e8db3 100644 --- a/src/Listeners/RenderAnsiArtListener.php +++ b/src/Listeners/RenderAnsiArtListener.php @@ -52,7 +52,7 @@ class RenderAnsiArtListener extends AbstractListener * * @return void */ - public function handle(EventInterface $event, ApplicationInterface $application = null) + public function handle(EventInterface $event, ?ApplicationInterface $application = null) { // write the TechDivision ANSI art icon to the console diff --git a/src/Listeners/RenderDebugInfoListener.php b/src/Listeners/RenderDebugInfoListener.php index faf99a6b..0836ba2e 100644 --- a/src/Listeners/RenderDebugInfoListener.php +++ b/src/Listeners/RenderDebugInfoListener.php @@ -57,7 +57,7 @@ public function __construct(ConfigurationInterface $configuration) * * @return void */ - public function handle(EventInterface $event, ApplicationInterface $application = null) + public function handle(EventInterface $event, ?ApplicationInterface $application = null) { // abort if the application instance is not available diff --git a/src/Listeners/RenderOperationInfoListener.php b/src/Listeners/RenderOperationInfoListener.php index 32b3d71f..fff7e237 100644 --- a/src/Listeners/RenderOperationInfoListener.php +++ b/src/Listeners/RenderOperationInfoListener.php @@ -57,7 +57,7 @@ public function __construct(ConfigurationInterface $configuration) * * @return void */ - public function handle(EventInterface $event, ApplicationInterface $application = null) + public function handle(EventInterface $event, ?ApplicationInterface $application = null) { // write a warning for low performance, if XDebug extension is activated diff --git a/src/Listeners/RenderOperationReportListener.php b/src/Listeners/RenderOperationReportListener.php index 5e0f4800..6705859a 100644 --- a/src/Listeners/RenderOperationReportListener.php +++ b/src/Listeners/RenderOperationReportListener.php @@ -64,11 +64,11 @@ public function __construct(RegistryProcessorInterface $registryProcessor, Confi * Handle the event. * * @param \League\Event\EventInterface $event The event that triggered the listener - * @param \TechDivision\Import\ApplicationInterface $application The application instance + * @param \TechDivision\Import\ApplicationInterface|null $application The application instance * * @return void */ - public function handle(EventInterface $event, ApplicationInterface $application = null) + public function handle(EventInterface $event, ?ApplicationInterface $application = null) { // load the registry processor diff --git a/src/Listeners/Renderer/Debug/AbstractDebugRenderer.php b/src/Listeners/Renderer/Debug/AbstractDebugRenderer.php index 426381b6..10e94c96 100644 --- a/src/Listeners/Renderer/Debug/AbstractDebugRenderer.php +++ b/src/Listeners/Renderer/Debug/AbstractDebugRenderer.php @@ -76,7 +76,7 @@ public function __construct( RegistryProcessorInterface $registryProcessor, ConfigurationInterface $configuration, Collection $systemLoggers, - ContainerInterface $container = null + ?ContainerInterface $container = null ) { $this->registryProcessor = $registryProcessor; $this->configuration = $configuration; diff --git a/src/Listeners/Renderer/Debug/ConfigurationFileRenderer.php b/src/Listeners/Renderer/Debug/ConfigurationFileRenderer.php index b0ae786d..9077eea1 100644 --- a/src/Listeners/Renderer/Debug/ConfigurationFileRenderer.php +++ b/src/Listeners/Renderer/Debug/ConfigurationFileRenderer.php @@ -32,11 +32,11 @@ class ConfigurationFileRenderer extends AbstractDebugRenderer /** * Renders the data to some output, e. g. the console or a logger. * - * @param string $serial The serial of the import to render the dump artefacts for + * @param string|null $serial The serial of the import to render the dump artefacts for * * @return void */ - public function render(string $serial = null) + public function render(?string $serial = null) { // load the actual status diff --git a/src/Listeners/Renderer/Debug/GenericDebugCompositeRenderer.php b/src/Listeners/Renderer/Debug/GenericDebugCompositeRenderer.php index b3e7c8b3..f3371ab9 100644 --- a/src/Listeners/Renderer/Debug/GenericDebugCompositeRenderer.php +++ b/src/Listeners/Renderer/Debug/GenericDebugCompositeRenderer.php @@ -27,15 +27,14 @@ */ class GenericDebugCompositeRenderer extends GenericCompositeRenderer { - /** * Renders the data to some output, e. g. the console or a logger. * - * @param string $serial The serial of the import to render the dump artefacts for + * @param string|null $serial The serial of the import to render the dump artefacts for * * @return void */ - public function render(string $serial = null) + public function render(?string $serial = null) { foreach ($this->getRenderers() as $renderer) { $renderer->render($serial); diff --git a/src/Listeners/Renderer/Debug/InfoFileRenderer.php b/src/Listeners/Renderer/Debug/InfoFileRenderer.php index e887da46..00c472e2 100644 --- a/src/Listeners/Renderer/Debug/InfoFileRenderer.php +++ b/src/Listeners/Renderer/Debug/InfoFileRenderer.php @@ -31,11 +31,11 @@ class InfoFileRenderer extends AbstractDebugRenderer /** * Renders the data to some output, e. g. the console or a logger. * - * @param string $serial The serial of the import to render the dump artefacts for + * @param string|null $serial The serial of the import to render the dump artefacts for * * @return void */ - public function render(string $serial = null) + public function render(?string $serial = null) { // load the actual status diff --git a/src/Listeners/Renderer/Debug/ReportFileRenderer.php b/src/Listeners/Renderer/Debug/ReportFileRenderer.php index fcd12fb4..1daab2f3 100644 --- a/src/Listeners/Renderer/Debug/ReportFileRenderer.php +++ b/src/Listeners/Renderer/Debug/ReportFileRenderer.php @@ -35,7 +35,7 @@ class ReportFileRenderer extends AbstractDebugRenderer * * @return void */ - public function render(string $serial = null) + public function render(?string $serial = null) { // load the actual status diff --git a/src/Listeners/StopValidationListener.php b/src/Listeners/StopValidationListener.php index 5b704b80..fd03cde4 100644 --- a/src/Listeners/StopValidationListener.php +++ b/src/Listeners/StopValidationListener.php @@ -57,7 +57,7 @@ public function __construct(RegistryProcessorInterface $registryProcessor) * * @return void */ - public function handle(EventInterface $event, PluginInterface $plugin = null) + public function handle(EventInterface $event, ?PluginInterface $plugin = null) { // load the validations from the registry diff --git a/src/Listeners/ValidateHeaderRowListener.php b/src/Listeners/ValidateHeaderRowListener.php index 949665f0..8c5c4427 100644 --- a/src/Listeners/ValidateHeaderRowListener.php +++ b/src/Listeners/ValidateHeaderRowListener.php @@ -39,7 +39,7 @@ class ValidateHeaderRowListener extends AbstractListener * * @return void */ - public function handle(EventInterface $event, SubjectInterface $subject = null) + public function handle(EventInterface $event, ?SubjectInterface $subject = null) { // load the header mappings from the subject instance diff --git a/src/Loaders/ColumnMetadataLoader.php b/src/Loaders/ColumnMetadataLoader.php index 4148463c..04363b49 100644 --- a/src/Loaders/ColumnMetadataLoader.php +++ b/src/Loaders/ColumnMetadataLoader.php @@ -49,7 +49,7 @@ class ColumnMetadataLoader implements LoaderInterface * @param \TechDivision\Import\Dbal\Connection\ConnectionInterface $connection The DB connection instance used to load the table metadata * @param \TechDivision\Import\Dbal\Utils\TablePrefixUtilInterface|null $tablePrefixUtil Table prefix utility */ - public function __construct(ConnectionInterface $connection, TablePrefixUtilInterface $tablePrefixUtil = null) + public function __construct(ConnectionInterface $connection, ?TablePrefixUtilInterface $tablePrefixUtil = null) { // use in load function for backword compatibility $this->tablePrefixUtil = $tablePrefixUtil; diff --git a/src/Loaders/ConfigurationValueLoader.php b/src/Loaders/ConfigurationValueLoader.php index cf496c71..17a0feff 100644 --- a/src/Loaders/ConfigurationValueLoader.php +++ b/src/Loaders/ConfigurationValueLoader.php @@ -60,11 +60,11 @@ protected function getConfigurationKey() /** * Loads and returns the configuration value for the key the instance has been initialized with. * - * @param \TechDivision\Import\Configuration\ParamsConfigurationInterface $configuration The configuration instance to load the value from + * @param \TechDivision\Import\Configuration\ParamsConfigurationInterface|null $configuration The configuration instance to load the value from * * @return \ArrayAccess The array with the configuration value */ - public function load(ParamsConfigurationInterface $configuration = null) + public function load(?ParamsConfigurationInterface $configuration = null) { // return an empty array if the param has NOT been set diff --git a/src/Loaders/EavAttributeOptionValueLoader.php b/src/Loaders/EavAttributeOptionValueLoader.php index f2d7128f..cac431cd 100644 --- a/src/Loaders/EavAttributeOptionValueLoader.php +++ b/src/Loaders/EavAttributeOptionValueLoader.php @@ -63,12 +63,12 @@ public function __construct(ImportProcessorInterface $importProcessor) /** * Loads and returns data the custom validation data. * - * @param \TechDivision\Import\Configuration\ParamsConfigurationInterface $configuration The configuration instance to load the validations from - * @param \TechDivision\Import\Subjects\SubjectInterface $subject The subject instance to load the validations from + * @param \TechDivision\Import\Configuration\ParamsConfigurationInterface|null $configuration The configuration instance to load the validations from + * @param \TechDivision\Import\Subjects\SubjectInterface|null $subject The subject instance to load the validations from * * @return \ArrayAccess The array with the data */ - public function load(SubjectConfigurationInterface $configuration = null, SubjectInterface $subject = null) + public function load(?SubjectConfigurationInterface $configuration = null, ?SubjectInterface $subject = null) { // load the entity type code from the passed subject configuration if ($subject) { diff --git a/src/Loaders/FilesystemLoader.php b/src/Loaders/FilesystemLoader.php index 66b54ebb..285e7156 100644 --- a/src/Loaders/FilesystemLoader.php +++ b/src/Loaders/FilesystemLoader.php @@ -57,7 +57,7 @@ public function __construct(FilesystemAdapterInterface $filesystemAdapter) * * @return array The array with the data */ - public function load(string $pattern = null) : array + public function load(?string $pattern = null) : array { return $this->getFilesystemAdapter()->glob($pattern ? $pattern : getcwd() . DIRECTORY_SEPARATOR . '*'); } diff --git a/src/Loaders/FilteredByExecutionContextEntityTypeCodeLoader.php b/src/Loaders/FilteredByExecutionContextEntityTypeCodeLoader.php index 45034dd9..eabafe88 100644 --- a/src/Loaders/FilteredByExecutionContextEntityTypeCodeLoader.php +++ b/src/Loaders/FilteredByExecutionContextEntityTypeCodeLoader.php @@ -48,11 +48,11 @@ public function __construct(LoaderInterface $loader) /** * Loads and returns data the custom validation data. * - * @param \TechDivision\Import\Configuration\ParamsConfigurationInterface $configuration The configuration instance to load the validations from + * @param SubjectConfigurationInterface|null $configuration The configuration instance to load the validations from * * @return \ArrayAccess The array with the data */ - public function load(SubjectConfigurationInterface $configuration = null) + public function load(?SubjectConfigurationInterface $configuration = null) { return $this->loader->load($configuration->getExecutionContext()->getEntityTypeCode()); } diff --git a/src/Loaders/FilteredLoader.php b/src/Loaders/FilteredLoader.php index 41f4344e..a5b55218 100644 --- a/src/Loaders/FilteredLoader.php +++ b/src/Loaders/FilteredLoader.php @@ -61,7 +61,7 @@ class FilteredLoader implements FilteredLoaderInterface * @param \TechDivision\Import\Loaders\LoaderInterface $loader The parent loader instance * @param \TechDivision\Import\Loaders\Filters\FilterImplInterface|null $filterImpl The filter instance to use */ - public function __construct(LoaderInterface $loader, FilterImplInterface $filterImpl = null) + public function __construct(LoaderInterface $loader, ?FilterImplInterface $filterImpl = null) { $this->loader = $loader; $this->filterImpl = $filterImpl ?? new ArrayFilterImpl(); @@ -119,7 +119,7 @@ public function getSizeBeforeFiltersHaveBeenApplied() : int * * @return array The array with the data */ - public function load(string $pattern = null) : array + public function load(?string $pattern = null) : array { // load the data from the parent loader diff --git a/src/Loaders/Filters/PregMatchFilter.php b/src/Loaders/Filters/PregMatchFilter.php index fdf1feb7..e3230f36 100644 --- a/src/Loaders/Filters/PregMatchFilter.php +++ b/src/Loaders/Filters/PregMatchFilter.php @@ -171,7 +171,7 @@ public function addMatches(array $matches) : void * * @return bool TRUE if the match with the passed name and key is available, else FALSE */ - public function hasMatch(string $name, string $key = null) : bool + public function hasMatch(string $name, ?string $key = null) : bool { return isset($this->matches[$key ?? sizeof($this->matches) - 1][$name]); } @@ -186,7 +186,7 @@ public function hasMatch(string $name, string $key = null) : bool * @return string The match itself * @throws \InvalidArgumentException Is thrown the value of the match with the passed name and key is not available */ - public function getMatch(string $name, string $key = null) : string + public function getMatch(string $name, ?string $key = null) : string { // use the passed key or the key of the last match diff --git a/src/Loaders/HeaderMappingLoader.php b/src/Loaders/HeaderMappingLoader.php index 4b637791..9acbd005 100644 --- a/src/Loaders/HeaderMappingLoader.php +++ b/src/Loaders/HeaderMappingLoader.php @@ -52,7 +52,7 @@ public function __construct(ConfigurationInterface $configuration) * * @return array The array with the values */ - public function load(string $entityTypeCode = null) : array + public function load(?string $entityTypeCode = null) : array { return isset($this->headerMappings[$entityTypeCode]) ? $this->headerMappings[$entityTypeCode] : array(); } diff --git a/src/Loaders/MysqlVariablesLoader.php b/src/Loaders/MysqlVariablesLoader.php index e1c79b39..61a1c345 100644 --- a/src/Loaders/MysqlVariablesLoader.php +++ b/src/Loaders/MysqlVariablesLoader.php @@ -119,7 +119,7 @@ public function __construct(ConnectionInterface $connection, $variableScope = 'G * * @return \ArrayAccess The array with the data */ - public function load(SubjectConfigurationInterface $configuration = null) + public function load(?SubjectConfigurationInterface $configuration = null) { // initialize the array for the rows diff --git a/src/Loaders/PregMatchFilteredLoader.php b/src/Loaders/PregMatchFilteredLoader.php index 3d72f437..d547a748 100644 --- a/src/Loaders/PregMatchFilteredLoader.php +++ b/src/Loaders/PregMatchFilteredLoader.php @@ -126,7 +126,7 @@ public function reset() : void * @return string The match itself * @throws \InvalidArgumentException Is thrown the value of the match with the passed name and key is not available */ - public function getMatch(string $name, string $key = null) : string + public function getMatch(string $name, ?string $key = null) : string { // load the matches from all filters @@ -211,7 +211,7 @@ public function getFilters() : array * * @return array The array with the data */ - public function load(string $pattern = null) : array + public function load(?string $pattern = null) : array { return $this->getLoader()->load($pattern); } diff --git a/src/Loaders/PregMatchFilteredLoaderInterface.php b/src/Loaders/PregMatchFilteredLoaderInterface.php index 4c47009a..29a81529 100644 --- a/src/Loaders/PregMatchFilteredLoaderInterface.php +++ b/src/Loaders/PregMatchFilteredLoaderInterface.php @@ -58,5 +58,5 @@ public function reset() : void; * @return string The match itself * @throws \InvalidArgumentException Is thrown the value of the match with the passed name and key is not available */ - public function getMatch(string $name, string $key = null) : string; + public function getMatch(string $name, ?string $key = null) : string; } diff --git a/src/Loaders/ProposedOkFilenameLoader.php b/src/Loaders/ProposedOkFilenameLoader.php index 1a4a0925..8fd9ef7d 100644 --- a/src/Loaders/ProposedOkFilenameLoader.php +++ b/src/Loaders/ProposedOkFilenameLoader.php @@ -76,15 +76,15 @@ class ProposedOkFilenameLoader extends FilteredLoader implements FilteredLoaderI * Initializes the file handler instance. * * @param \TechDivision\Import\Loaders\FilteredLoaderInterface $loader The parent loader instance - * @param \TechDivision\Import\Loaders\Filters\FilterImplInterface $filterImpl The filter instance to use - * @param \TechDivision\Import\Loaders\Sorters\SorterImplInterface $sorterImpl The sorter instance to use - * @param \TechDivision\Import\Handlers\GenericFileHandlerInterface $genericFileHandler The generic file handler instance + * @param \TechDivision\Import\Loaders\Filters\FilterImplInterface|null $filterImpl The filter instance to use + * @param \TechDivision\Import\Loaders\Sorters\SorterImplInterface|null $sorterImpl The sorter instance to use + * @param \TechDivision\Import\Handlers\GenericFileHandlerInterface|null $genericFileHandler The generic file handler instance */ public function __construct( FilteredLoaderInterface $loader, - FilterImplInterface $filterImpl = null, - SorterImplInterface $sorterImpl = null, - GenericFileHandlerInterface $genericFileHandler = null + ?FilterImplInterface $filterImpl = null, + ?SorterImplInterface $sorterImpl = null, + ?GenericFileHandlerInterface $genericFileHandler = null ) { // initialize the sorter instance @@ -473,7 +473,7 @@ public function setFileResolverConfiguration(FileResolverConfigurationInterface * * @return array The array with the data */ - public function load(string $pattern = null) : array + public function load(?string $pattern = null) : array { // load the pattern to filter the available CSV files with. We filter diff --git a/src/Loaders/ProposedOkFilenameLoaderFactory.php b/src/Loaders/ProposedOkFilenameLoaderFactory.php index b6b183cb..523e5f8b 100644 --- a/src/Loaders/ProposedOkFilenameLoaderFactory.php +++ b/src/Loaders/ProposedOkFilenameLoaderFactory.php @@ -113,7 +113,7 @@ protected function getSourceDir(FilesystemAdapterInterface $filesystemAdapter) : * * @return \TechDivision\Import\Loaders\LoaderInterface The loader instance */ - public function createLoader(SubjectConfigurationInterface $subject = null) : LoaderInterface + public function createLoader(?SubjectConfigurationInterface $subject = null) : LoaderInterface { // load the filesystem adapter instance diff --git a/src/Loaders/SortedLoader.php b/src/Loaders/SortedLoader.php index ba93fd38..daf17b7c 100644 --- a/src/Loaders/SortedLoader.php +++ b/src/Loaders/SortedLoader.php @@ -54,7 +54,7 @@ class SortedLoader implements SortedLoaderInterface * @param \TechDivision\Import\Loaders\LoaderInterface $loader The parent loader instance * @param \TechDivision\Import\Loaders\Sorters\SorterImplInterface|null $sorterImpl The sorter instance to use */ - public function __construct(LoaderInterface $loader, SorterImplInterface $sorterImpl = null) + public function __construct(LoaderInterface $loader, ?SorterImplInterface $sorterImpl = null) { $this->loader = $loader; $this->sorterImpl = $sorterImpl ?? new UasortImpl(); @@ -92,7 +92,7 @@ public function getSorters() : array * * @return \ArrayAccess The array with the data */ - public function load(string $pattern = null) : \ArrayAccess + public function load(?string $pattern = null) : \ArrayAccess { // sort the files loaded by the parent loader instance diff --git a/src/Loggers/Mailer/SendmailTransportMailerFactory.php b/src/Loggers/Mailer/SendmailTransportMailerFactory.php new file mode 100644 index 00000000..0c1d5e81 --- /dev/null +++ b/src/Loggers/Mailer/SendmailTransportMailerFactory.php @@ -0,0 +1,57 @@ + + * @copyright 2016 TechDivision GmbH + * @license https://opensource.org/licenses/MIT + * @link https://github.com/techdivision/import + * @link http://www.techdivision.com + */ + +namespace TechDivision\Import\Loggers\Mailer; + +use Exception; +use Symfony\Component\Mailer\Mailer; +use Symfony\Component\Mailer\MailerInterface; +use Symfony\Component\Mailer\Transport\SendmailTransport; +use TechDivision\Import\Utils\MailerKeys; +use TechDivision\Import\Configuration\Mailer\TransportConfigurationInterface; + +/** + * Factory implementation for a mailer with a simple sendmail transport (Symfony Mailer). + * + * @author Tim Wagner + * @copyright 2016 TechDivision GmbH + * @license https://opensource.org/licenses/MIT + * @link https://github.com/techdivision/import + * @link http://www.techdivision.com + */ +class SendmailTransportMailerFactory implements TransportMailerFactoryInterface +{ + /** + * Creates a new mailer instance based on the passed transport configuration. + * + * @param TransportConfigurationInterface $transportConfiguration The mailer configuration + * + * @return MailerInterface The mailer instance + * @throws Exception + */ + public function factory(TransportConfigurationInterface $transportConfiguration) + { + // initialize and load the sendmail command parameter + $command = '/usr/sbin/sendmail -bs'; + if ($transportConfiguration->hasParam(MailerKeys::COMMAND)) { + $command = $transportConfiguration->getParam(MailerKeys::COMMAND); + } + + // initialize and create the mailer transport instance + $transport = new SendmailTransport($command); + + // initialize, create and return the Symfony mailer instance + return new Mailer($transport); + } +} diff --git a/src/Loggers/Mailer/SmtpTransportMailerFactory.php b/src/Loggers/Mailer/SmtpTransportMailerFactory.php new file mode 100644 index 00000000..7bee8455 --- /dev/null +++ b/src/Loggers/Mailer/SmtpTransportMailerFactory.php @@ -0,0 +1,105 @@ + + * @copyright 2016 TechDivision GmbH + * @license https://opensource.org/licenses/MIT + * @link https://github.com/techdivision/import + * @link http://www.techdivision.com + */ + +namespace TechDivision\Import\Loggers\Mailer; + +use Exception; +use Symfony\Component\Mailer\Mailer; +use Symfony\Component\Mailer\MailerInterface; +use Symfony\Component\Mailer\Transport; +use TechDivision\Import\Utils\MailerKeys; +use TechDivision\Import\Configuration\Mailer\TransportConfigurationInterface; + +/** + * Factory implementation for a mailer with SMTP transport (Symfony Mailer). + * + * @author Tim Wagner + * @copyright 2016 TechDivision GmbH + * @license https://opensource.org/licenses/MIT + * @link https://github.com/techdivision/import + * @link http://www.techdivision.com + */ +class SmtpTransportMailerFactory implements TransportMailerFactoryInterface +{ + /** + * Creates a new mailer instance based on the passed transport configuration. + * + * @param TransportConfigurationInterface $transportConfiguration The mailer configuration + * + * @return Mailer|MailerInterface The mailer instance + * @throws Exception + */ + public function factory(TransportConfigurationInterface $transportConfiguration) + { + // load the SMTP host from the configuration + if ($transportConfiguration->hasParam(MailerKeys::SMTP_HOST)) { + $smtpHost = $transportConfiguration->getParam(MailerKeys::SMTP_HOST); + } else { + $smtpHost = 'localhost'; + } + + // load the SMTP port from the configuration + if ($transportConfiguration->hasParam(MailerKeys::SMTP_PORT)) { + $smtpPort = $transportConfiguration->getParam(MailerKeys::SMTP_PORT); + } else { + $smtpPort = null; + } + + // load the SMTP security from the configuration + if ($transportConfiguration->hasParam(MailerKeys::SMTP_SECURITY)) { + $smtpSecurity = $transportConfiguration->getParam(MailerKeys::SMTP_SECURITY); + } else { + $smtpSecurity = null; + } + + // load optional authentication settings + if ($transportConfiguration->hasParam(MailerKeys::SMTP_USERNAME)) { + $username = $transportConfiguration->getParam(MailerKeys::SMTP_USERNAME); + } else { + $username = null; + } + + if ($transportConfiguration->hasParam(MailerKeys::SMTP_PASSWORD)) { + $password = $transportConfiguration->getParam(MailerKeys::SMTP_PASSWORD); + } else { + $password = null; + } + + if ($transportConfiguration->hasParam(MailerKeys::SMTP_AUTH_MODE)) { + $authMode = $transportConfiguration->getParam(MailerKeys::SMTP_AUTH_MODE); + } else { + $authMode = null; + } + + // build DSN + $auth = ''; + if (!empty($username)) { + $auth = sprintf('%s:%s@', rawurlencode($username), rawurlencode((string)$password)); + } + $hostPort = sprintf('%s%s', $smtpHost, $smtpPort ? ":$smtpPort" : ''); + $query = []; + if (!empty($smtpSecurity)) { + $query[] = sprintf('encryption=%s', $smtpSecurity); + } + if (!empty($authMode)) { + $query[] = sprintf('auth_mode=%s', $authMode); + } + $dsn = sprintf('smtp://%s%s%s%s', $auth, $hostPort, $query ? '?' : '', implode('&', $query)); + + // create Symfony Mailer from DSN + $transport = Transport::fromDsn($dsn); + + return new Mailer($transport); + } +} diff --git a/src/Loggers/SwiftMailer/TransportMailerFactoryInterface.php b/src/Loggers/Mailer/TransportMailerFactoryInterface.php similarity index 60% rename from src/Loggers/SwiftMailer/TransportMailerFactoryInterface.php rename to src/Loggers/Mailer/TransportMailerFactoryInterface.php index 686d1156..9b323d02 100644 --- a/src/Loggers/SwiftMailer/TransportMailerFactoryInterface.php +++ b/src/Loggers/Mailer/TransportMailerFactoryInterface.php @@ -1,7 +1,7 @@ * @copyright 201 TechDivision GmbH @@ -29,11 +29,11 @@ interface TransportMailerFactoryInterface { /** - * Creates a new swift mailer instance based on the passed transport configuration. + * Creates a new mailer instance based on the passed transport configuration. * - * @param \TechDivision\Import\Configuration\SwiftMailer\TransportConfigurationInterface $transportConfiguration The mailer configuration + * @param TransportConfigurationInterface $transportConfiguration The mailer configuration * - * @return \Swift_Mailer The mailer instance + * @return mixed The mailer instance */ public function factory(TransportConfigurationInterface $transportConfiguration); } diff --git a/src/Loggers/SwiftMailerHandlerFactory.php b/src/Loggers/MailerHandlerFactory.php similarity index 60% rename from src/Loggers/SwiftMailerHandlerFactory.php rename to src/Loggers/MailerHandlerFactory.php index cac064a2..0e2fe009 100644 --- a/src/Loggers/SwiftMailerHandlerFactory.php +++ b/src/Loggers/MailerHandlerFactory.php @@ -1,7 +1,7 @@ * @copyright 2019 TechDivision GmbH @@ -31,7 +34,7 @@ * @link https://github.com/techdivision/import * @link http://www.techdivision.com */ -class SwiftMailerHandlerFactory implements HandlerFactoryInterface +class MailerHandlerFactory implements HandlerFactoryInterface { /** @@ -86,22 +89,22 @@ protected function getSystemName() * @param \TechDivision\Import\Configuration\Logger\HandlerConfigurationInterface $handlerConfiguration The handler configuration * * @return \Monolog\Handler\HandlerInterface The handler instance + * @throws Exception */ public function factory(HandlerConfigurationInterface $handlerConfiguration) { + // load the mailer configuration + $mailerConfiguration = $handlerConfiguration->getMailer(); - // load the swift mailer configuration - $swiftMailerConfiguration = $handlerConfiguration->getSwiftMailer(); - - // create the swift mailer (factory) instance - $possibleSwiftMailer = $this->getContainer()->get($swiftMailerConfiguration->getId()); + // create the mailer (factory) instance + $possibleMailer = $this->getContainer()->get($mailerConfiguration->getId()); - // query whether or not we've a factory or the instance - /** @var \Swift_Mailer $swiftMailer */ - if ($possibleSwiftMailer instanceof TransportMailerFactoryInterface) { - $swiftMailer = $possibleSwiftMailer->factory($swiftMailerConfiguration->getTransport()); + // resolve to a MailerInterface + if ($possibleMailer instanceof TransportMailerFactoryInterface) { + /** @var MailerInterface $mailer */ + $mailer = $possibleMailer->factory($mailerConfiguration->getTransport()); } else { - $swiftMailer = $possibleSwiftMailer; + $mailer = $possibleMailer; } // load the generic logger configuration @@ -109,20 +112,25 @@ public function factory(HandlerConfigurationInterface $handlerConfiguration) $logLevel = $handlerConfiguration->getParam(LoggerKeys::LOG_LEVEL); // load sender/receiver configuration - $to = $swiftMailerConfiguration->getParam(SwiftMailerKeys::TO); - $from = $swiftMailerConfiguration->getParam(SwiftMailerKeys::FROM); - $subject = $swiftMailerConfiguration->getParam(SwiftMailerKeys::SUBJECT); - $contentType = $swiftMailerConfiguration->getParam(SwiftMailerKeys::CONTENT_TYPE); - - // initialize the message template - $message = $swiftMailer->createMessage() - ->setSubject(sprintf('[%s] %s', $this->getSystemName(), $subject)) - ->setFrom($from) - ->setTo($to) - ->setBody('', $contentType); - - // initialize the handler node - $reflectionClass = new \ReflectionClass(SwiftMailerHandler::class); - return $reflectionClass->newInstanceArgs(array($swiftMailer, $message, $logLevel, $bubble)); + $to = $mailerConfiguration->getParam(MailerKeys::TO); + $from = $mailerConfiguration->getParam(MailerKeys::FROM); + $subject = $mailerConfiguration->getParam(MailerKeys::SUBJECT); + $contentType = $mailerConfiguration->getParam(MailerKeys::CONTENT_TYPE); + + // initialize the message template for Symfony Mailer + $email = (new Email()) + ->subject(sprintf('[%s] %s', $this->getSystemName(), $subject)) + ->from($from) + ->to(...(array) $to); + + // initialize body placeholder to match configured content type + if ($contentType === 'text/html') { + $email->html(''); + } else { + $email->text(''); + } + + // initialize and return the handler + return new SymfonyMailerHandler($mailer, $email, $logLevel, $bubble); } } diff --git a/src/Loggers/SwiftMailer/SendmailTransportMailerFactory.php b/src/Loggers/SwiftMailer/SendmailTransportMailerFactory.php deleted file mode 100644 index 4b8ac9b8..00000000 --- a/src/Loggers/SwiftMailer/SendmailTransportMailerFactory.php +++ /dev/null @@ -1,54 +0,0 @@ - - * @copyright 2016 TechDivision GmbH - * @license https://opensource.org/licenses/MIT - * @link https://github.com/techdivision/import - * @link http://www.techdivision.com - */ - -namespace TechDivision\Import\Loggers\SwiftMailer; - -use TechDivision\Import\Utils\SwiftMailerKeys; -use TechDivision\Import\Configuration\SwiftMailer\TransportConfigurationInterface; - -/** - * Factory implementation for a swift mailer with a simple sendmail transport. - * - * @author Tim Wagner - * @copyright 2016 TechDivision GmbH - * @license https://opensource.org/licenses/MIT - * @link https://github.com/techdivision/import - * @link http://www.techdivision.com - */ -class SendmailTransportMailerFactory implements TransportMailerFactoryInterface -{ - - /** - * Creates a new swift mailer instance based on the passed transport configuration. - * - * @param \TechDivision\Import\Configuration\SwiftMailer\TransportConfigurationInterface $transportConfiguration The mailer configuration - * - * @return \Swift_Mailer The mailer instance - */ - public function factory(TransportConfigurationInterface $transportConfiguration) - { - - // initialize and load the sendmail command parameter - $command = '/usr/sbin/sendmail -bs'; - if ($transportConfiguration->hasParam(SwiftMailerKeys::COMMAND)) { - $command = $transportConfiguration->getParam(SwiftMailerKeys::COMMAND); - } - - // initialize and create the mailer transport instance - $transport = new \Swift_SendmailTransport($command); - - // initialize, create and return the swift mailer instance - return new \Swift_Mailer($transport); - } -} diff --git a/src/Loggers/SwiftMailer/SmtpTransportMailerFactory.php b/src/Loggers/SwiftMailer/SmtpTransportMailerFactory.php deleted file mode 100644 index 77a8d825..00000000 --- a/src/Loggers/SwiftMailer/SmtpTransportMailerFactory.php +++ /dev/null @@ -1,91 +0,0 @@ - - * @copyright 2016 TechDivision GmbH - * @license https://opensource.org/licenses/MIT - * @link https://github.com/techdivision/import - * @link http://www.techdivision.com - */ - -namespace TechDivision\Import\Loggers\SwiftMailer; - -use TechDivision\Import\Utils\SwiftMailerKeys; -use TechDivision\Import\Configuration\SwiftMailer\TransportConfigurationInterface; - -/** - * Factory implementation for a swift mailer with SMTP transport. - * - * @author Tim Wagner - * @copyright 2016 TechDivision GmbH - * @license https://opensource.org/licenses/MIT - * @link https://github.com/techdivision/import - * @link http://www.techdivision.com - */ -class SmtpTransportMailerFactory implements TransportMailerFactoryInterface -{ - - /** - * Creates a new swift mailer instance based on the passed transport configuration. - * - * @param \TechDivision\Import\Configuration\SwiftMailer\TransportConfigurationInterface $transportConfiguration The mailer configuration - * - * @return \Swift_Mailer The mailer instance - */ - public function factory(TransportConfigurationInterface $transportConfiguration) - { - - // load the SMTP host from the configuration - $smtpHost = null; - if ($transportConfiguration->hasParam(SwiftMailerKeys::SMTP_HOST)) { - $smtpHost = $transportConfiguration->getParam(SwiftMailerKeys::SMTP_HOST); - } - - // load the SMTP port from the configuration - $smtpPort = null; - if ($transportConfiguration->hasParam(SwiftMailerKeys::SMTP_PORT)) { - $smtpPort = $transportConfiguration->getParam(SwiftMailerKeys::SMTP_PORT); - } - - // load the SMTP security from the configuration - $smtpSecurity = null; - if ($transportConfiguration->hasParam(SwiftMailerKeys::SMTP_SECURITY)) { - $smtpSecurity = $transportConfiguration->getParam(SwiftMailerKeys::SMTP_SECURITY); - } - - // initialize and create the mailer transport instance - $transport = new \Swift_SmtpTransport($smtpHost, $smtpPort, $smtpSecurity); - - // query whether or not if a SMTP authentication mode has been specified - if ($transportConfiguration->hasParam(SwiftMailerKeys::SMTP_AUTH_MODE)) { - // load the authentication mode from the configuration - $transport->setAuthMode($transportConfiguration->getParam(SwiftMailerKeys::SMTP_AUTH_MODE)); - // set the stream context options, e. g. to allow self signed certificates - $transport->setStreamOptions( - array( - 'ssl' => array( - 'allow_self_signed' => true, - 'verify_peer' => false - ) - ) - ); - - // load the SMTP username from the configuration - if ($transportConfiguration->hasParam(SwiftMailerKeys::SMTP_USERNAME)) { - $transport->setUsername($transportConfiguration->getParam(SwiftMailerKeys::SMTP_USERNAME)); - } - - // load the SMTP password from the configuration - if ($transportConfiguration->hasParam(SwiftMailerKeys::SMTP_PASSWORD)) { - $transport->setPassword($transportConfiguration->getParam(SwiftMailerKeys::SMTP_PASSWORD)); - } - } - - // initialize, create and return the swift mailer instance - return new \Swift_Mailer($transport); - } -} diff --git a/src/Observers/AbstractObserver.php b/src/Observers/AbstractObserver.php index 6c2bd531..6c348207 100644 --- a/src/Observers/AbstractObserver.php +++ b/src/Observers/AbstractObserver.php @@ -56,9 +56,9 @@ abstract class AbstractObserver implements ObserverInterface /** * Initializes the observer with the state detector instance. * - * @param \TechDivision\Import\Observers\StateDetectorInterface $stateDetector The state detector instance + * @param \TechDivision\Import\Observers\StateDetectorInterface|null $stateDetector The state detector instance */ - public function __construct(StateDetectorInterface $stateDetector = null) + public function __construct(?StateDetectorInterface $stateDetector = null) { $this->stateDetector = $stateDetector; } @@ -224,7 +224,7 @@ protected function appendExceptionSuffix($message = null, $filename = null, $lin * line number and column name and use it for a detailed exception message. * * @param string $columnName The column name that should be resolved - * @param \Exception $parent The exception we want to wrap + * @param \Exception|null $parent The exception we want to wrap * @param string $className The class name of the exception type we want to wrap the parent one * * @return \Exception the wrapped exception @@ -233,7 +233,7 @@ protected function appendExceptionSuffix($message = null, $filename = null, $lin */ protected function wrapException( $columnName, - \Exception $parent = null, + ?\Exception $parent = null, $className = '\TechDivision\Import\Exceptions\WrappedColumnException' ) { return $this->getSubject()->wrapException($columnName, $parent, $className); diff --git a/src/Observers/AdditionalAttributeObserver.php b/src/Observers/AdditionalAttributeObserver.php index 54418c3e..eef6f7b6 100644 --- a/src/Observers/AdditionalAttributeObserver.php +++ b/src/Observers/AdditionalAttributeObserver.php @@ -53,7 +53,7 @@ class AdditionalAttributeObserver extends AbstractObserver implements ObserverFa */ public function __construct( SerializerFactoryInterface $serializerFactory, - StateDetectorInterface $stateDetector = null + ?StateDetectorInterface $stateDetector = null ) { // initialize the bunch processor and the attribute loader instance diff --git a/src/Observers/DynamicAttributeObserverInterface.php b/src/Observers/DynamicAttributeObserverInterface.php index 0ed82466..9b8963a7 100644 --- a/src/Observers/DynamicAttributeObserverInterface.php +++ b/src/Observers/DynamicAttributeObserverInterface.php @@ -55,7 +55,7 @@ public function hasValue($name); * * @return mixed|null The, almost formatted, value */ - public function getValue($name, $default = null, callable $callback = null); + public function getValue($name, $default = null, ?callable $callback = null); /** * Cast's the passed value based on the backend type information. diff --git a/src/Observers/EntityMergers/CleanUpColumnsEntityMerger.php b/src/Observers/EntityMergers/CleanUpColumnsEntityMerger.php index 0cccd441..321cf828 100644 --- a/src/Observers/EntityMergers/CleanUpColumnsEntityMerger.php +++ b/src/Observers/EntityMergers/CleanUpColumnsEntityMerger.php @@ -46,7 +46,7 @@ class CleanUpColumnsEntityMerger implements EntityMergerInterface * * @param \TechDivision\Import\Loaders\LoaderInterface|null $haederMappingLoader The loader for the virtual mappings */ - public function __construct(LoaderInterface $haederMappingLoader = null) + public function __construct(?LoaderInterface $haederMappingLoader = null) { $this->reverseHeaderMappings = array_merge( $this->reverseHeaderMappings, diff --git a/src/Plugins/AbstractPlugin.php b/src/Plugins/AbstractPlugin.php index 3a2b20fd..38dde35b 100644 --- a/src/Plugins/AbstractPlugin.php +++ b/src/Plugins/AbstractPlugin.php @@ -14,12 +14,14 @@ namespace TechDivision\Import\Plugins; +use Exception; +use Symfony\Component\Mailer\MailerInterface; use TechDivision\Import\Utils\LoggerKeys; use TechDivision\Import\ApplicationInterface; use TechDivision\Import\Configuration\PluginConfigurationInterface; use TechDivision\Import\Adapter\ImportAdapterInterface; use TechDivision\Import\Utils\RegistryKeys; -use TechDivision\Import\Loggers\SwiftMailer\TransportMailerFactoryInterface; +use TechDivision\Import\Loggers\Mailer\TransportMailerFactoryInterface; /** * Abstract plugin implementation. @@ -293,30 +295,31 @@ protected function removeDir($src) } /** - * Return's the configured swift mailer instance. + * Return's the configured mailer instance. * - * @return \Swift_Mailer|null The mailer instance + * @return MailerInterface|null The mailer instance + * @throws Exception */ - protected function getSwiftMailer() + protected function getMailer() { + // the mailer configuration + $mailerConfiguration = $this->getPluginConfiguration()->getMailer(); - // the swift mailer configuration - if ($swiftMailerConfiguration = $this->getPluginConfiguration()->getSwiftMailer()) { - // create the swift mailer (factory) instance - $possibleSwiftMailer = $this->getApplication()->getContainer()->get($swiftMailerConfiguration->getId()); + if ($mailerConfiguration) { + // create the mailer (factory) instance + $possibleMailer = $this->getApplication()->getContainer()->get($mailerConfiguration->getId()); // query whether or not we've a factory or the instance - /** @var \Swift_Mailer $swiftMailer */ - if ($possibleSwiftMailer instanceof TransportMailerFactoryInterface) { - return $possibleSwiftMailer->factory($swiftMailerConfiguration->getTransport()); + if ($possibleMailer instanceof TransportMailerFactoryInterface) { + return $possibleMailer->factory($mailerConfiguration->getTransport()); } - if ($possibleSwiftMailer instanceof \Swift_Mailer) { - return $possibleSwiftMailer; + if ($possibleMailer instanceof MailerInterface) { + return $possibleMailer; } } // throw an exception if the configuration contains an invalid value - throw new \Exception('Can\'t create SwiftMailer from configuration'); + throw new \Exception('Can\'t create Mailer from configuration'); } } diff --git a/src/Plugins/MissingOptionValuesPlugin.php b/src/Plugins/MissingOptionValuesPlugin.php index 20c38a4f..fbc85c94 100644 --- a/src/Plugins/MissingOptionValuesPlugin.php +++ b/src/Plugins/MissingOptionValuesPlugin.php @@ -14,11 +14,13 @@ namespace TechDivision\Import\Plugins; +use Symfony\Component\Mailer\Exception\TransportExceptionInterface; +use Symfony\Component\Mime\Email; +use TechDivision\Import\Adapter\ExportAdapterInterface; +use TechDivision\Import\ApplicationInterface; use TechDivision\Import\Utils\ColumnKeys; +use TechDivision\Import\Utils\MailerKeys; use TechDivision\Import\Utils\RegistryKeys; -use TechDivision\Import\Utils\SwiftMailerKeys; -use TechDivision\Import\ApplicationInterface; -use TechDivision\Import\Adapter\ExportAdapterInterface; /** * Plugin that exports the missing option values to a CSV file. @@ -142,53 +144,40 @@ public function process() $this->addArtefacts(MissingOptionValuesPlugin::ARTEFACT_TYPE, $artefacts); $this->export(date('Ymd-His'), $counter = '01'); - // query whether or not a swift mailer has been registered - if ($swiftMailer = $this->getSwiftMailer()) { - // the swift mailer configuration - $swiftMailerConfiguration = $this->getPluginConfiguration()->getSwiftMailer(); + // query whether or not a mailer has been registered + if ($mailer = $this->getMailer()) { + // the mailer configuration + $mailerConfiguration = $this->getPluginConfiguration()->getMailer(); // create the message with the CSV with the missing option values - $message = $swiftMailer->createMessage() - ->setSubject(sprintf('[%s] %s', $this->getSystemName(), $swiftMailerConfiguration->getParam(SwiftMailerKeys::SUBJECT))) - ->setFrom($swiftMailerConfiguration->getParam(SwiftMailerKeys::FROM)) - ->setTo($to = $swiftMailerConfiguration->getParam(SwiftMailerKeys::TO)) - ->setBody('The attached CSV file(s) contains the missing attribute option values'); + $from = $mailerConfiguration->getParam(MailerKeys::FROM); + $to = $mailerConfiguration->getParam(MailerKeys::TO); + $subject = sprintf('[%s] %s', $this->getSystemName(), $mailerConfiguration->getParam(MailerKeys::SUBJECT)); + $body = 'The attached CSV file(s) contains the missing attribute option values'; + $email = (new Email())->subject($subject)->from($from)->to(...(array)$to)->text($body); // load the exported filenames $exportedFilenames = $this->getExportAdapter()->getExportedFilenames(); // attach the CSV files with the missing option values foreach ($exportedFilenames as $filename) { - $message->attach(\Swift_Attachment::fromPath($filename)); - } - - // initialize the array with the failed recipients - $failedRecipients = array(); - $recipientsAccepted = 0; - - // send the mail - $recipientsAccepted = $swiftMailer->send($message, $failedRecipients); - - // query whether or not all recipients have been accepted - if (sizeof($failedRecipients) > 0) { - $this->getSystemLogger()->error(sprintf('Can\'t send mail to %s', implode(', ', $failedRecipients))); + $email->attachFromPath($filename); } - // if at least one recipient has been accepted - if ($recipientsAccepted > 0) { - // cast 'to' into an array if not already - is_array($to) ? : $to = (array) $to; - // remove the NOT accepted recipients - $acceptedRecipients = array_diff($to, $failedRecipients); + try { + // send the mail + $mailer->send($email); - // log a message with the successfull receivers + // log a message with the receivers + is_array($to) ?: $to = (array) $to; $this->getSystemLogger()->info( sprintf( - 'Mail successfully sent to %d recipient(s) (%s)', - $recipientsAccepted, - implode(', ', $acceptedRecipients) + 'Mail successfully sent to recipient(s) (%s)', + implode(', ', $to) ) ); + } catch (TransportExceptionInterface $e) { + $this->getSystemLogger()->error(sprintf('Can\'t send mail: %s', $e->getMessage())); } } diff --git a/src/RowTrait.php b/src/RowTrait.php index aec39838..4373db9a 100644 --- a/src/RowTrait.php +++ b/src/RowTrait.php @@ -145,7 +145,7 @@ protected function setValue($name, $value) * * @return mixed|null The, almost formatted, value */ - public function getValue($name, $default = null, callable $callback = null) + public function getValue($name, $default = null, ?callable $callback = null) { // initialize the value diff --git a/src/Subjects/AbstractSubject.php b/src/Subjects/AbstractSubject.php index fc6e3d4d..8be9e837 100644 --- a/src/Subjects/AbstractSubject.php +++ b/src/Subjects/AbstractSubject.php @@ -1419,14 +1419,14 @@ public function hasOriginalData() * line number and column names and use it for a detailed exception message. * * @param array $columnNames The column names that should be resolved and wrapped - * @param \Exception $parent The exception we want to wrap + * @param \Exception|null $parent The exception we want to wrap * @param string $className The class name of the exception type we want to wrap the parent one * * @return \Exception the wrapped exception */ public function wrapException( array $columnNames = array(), - \Exception $parent = null, + ?\Exception $parent = null, $className = '\TechDivision\Import\Exceptions\WrappedColumnException' ) { diff --git a/src/Subjects/SubjectInterface.php b/src/Subjects/SubjectInterface.php index c1abed4a..410600b9 100644 --- a/src/Subjects/SubjectInterface.php +++ b/src/Subjects/SubjectInterface.php @@ -397,7 +397,7 @@ public function registerCallback(CallbackInterface $callback, $type); * * @return mixed|null The, almost formatted, value */ - public function getValue($name, $default = null, callable $callback = null); + public function getValue($name, $default = null, ?callable $callback = null); /** * Return's the store view code the create the product/attributes for. diff --git a/src/Utils/LoggerFactory.php b/src/Utils/LoggerFactory.php index cc33999b..34132a05 100644 --- a/src/Utils/LoggerFactory.php +++ b/src/Utils/LoggerFactory.php @@ -14,6 +14,7 @@ namespace TechDivision\Import\Utils; +use ReflectionException; use TechDivision\Import\Configuration\ConfigurationInterface; use TechDivision\Import\Configuration\LoggerConfigurationInterface; @@ -30,14 +31,15 @@ */ class LoggerFactory { - /** * Creates a new logger instance based on the passed logger configuration. * - * @param \TechDivision\Import\Configuration\ConfigurationInterface $configuration The system configuration - * @param \TechDivision\Import\Configuration\LoggerConfigurationInterface $loggerConfiguration The logger configuration + * @param \TechDivision\Import\Configuration\ConfigurationInterface $configuration The system configuration + * @param \TechDivision\Import\Configuration\LoggerConfigurationInterface $loggerConfiguration The logger + * configuration * * @return \Psr\Log\LoggerInterface The logger instance + * @throws ReflectionException */ public static function factory( ConfigurationInterface $configuration, @@ -63,25 +65,25 @@ public static function factory( $handlers = array(); /** @var \TechDivision\Import\Configuration\Logger\HandlerConfigurationInterface $handlerConfiguration */ foreach ($availableHandlers as $handlerConfiguration) { - // query whether or not, we've a swift mailer configuration - if ($swiftMailerConfiguration = $handlerConfiguration->getSwiftMailer()) { - // load the factory that creates the swift mailer instance - $factory = $swiftMailerConfiguration->getFactory(); - // create the swift mailer instance - $swiftMailer = $factory::factory($swiftMailerConfiguration); + // query whether or not, we've a mailer configuration + if ($mailerConfiguration = $handlerConfiguration->getMailer()) { + // load the factory that creates the mailer instance + $factory = $mailerConfiguration->getFactory(); + // create the mailer instance + $mailer = $factory::factory($mailerConfiguration); // load the generic logger configuration $bubble = $handlerConfiguration->getParam(LoggerKeys::BUBBLE); $logLevel = $handlerConfiguration->getParam(LoggerKeys::LOG_LEVEL); // load sender/receiver configuration - $to = $swiftMailerConfiguration->getParam(SwiftMailerKeys::TO); - $from = $swiftMailerConfiguration->getParam(SwiftMailerKeys::FROM); - $subject = $swiftMailerConfiguration->getParam(SwiftMailerKeys::SUBJECT); - $contentType = $swiftMailerConfiguration->getParam(SwiftMailerKeys::CONTENT_TYPE); + $to = $mailerConfiguration->getParam(MailerKeys::TO); + $from = $mailerConfiguration->getParam(MailerKeys::FROM); + $subject = $mailerConfiguration->getParam(MailerKeys::SUBJECT); + $contentType = $mailerConfiguration->getParam(MailerKeys::CONTENT_TYPE); // initialize the message template - $message = $swiftMailer->createMessage() + $message = $mailer->createMessage() ->setSubject(sprintf('[%s] %s', $configuration->getSystemName(), $subject)) ->setFrom($from) ->setTo($to) @@ -89,7 +91,7 @@ public static function factory( // initialize the handler node $reflectionClass = new \ReflectionClass($handlerConfiguration->getType()); - $handler = $reflectionClass->newInstanceArgs(array($swiftMailer, $message, $logLevel, $bubble)); + $handler = $reflectionClass->newInstanceArgs(array($mailer, $message, $logLevel, $bubble)); } else { // initialize the handler node $reflectionClass = new \ReflectionClass($handlerConfiguration->getType()); diff --git a/src/Utils/SwiftMailerKeys.php b/src/Utils/MailerKeys.php similarity index 73% rename from src/Utils/SwiftMailerKeys.php rename to src/Utils/MailerKeys.php index 4bde83bc..25a4f1de 100644 --- a/src/Utils/SwiftMailerKeys.php +++ b/src/Utils/MailerKeys.php @@ -1,7 +1,7 @@ * @copyright 2016 TechDivision GmbH @@ -23,7 +23,7 @@ * @link https://github.com/techdivision/import * @link http://www.techdivision.com */ -class SwiftMailerKeys +class MailerKeys { /** @@ -48,75 +48,75 @@ private function __clone() * * @var string */ - const TO = 'to'; + public const string TO = 'to'; /** * The key for param 'from'. * * @var string */ - const FROM = 'from'; + public const string FROM = 'from'; /** * The key for param 'subject'. * * @var string */ - const SUBJECT = 'subject'; + public const string SUBJECT = 'subject'; /** * The key for param 'content-type'. * * @var string */ - const CONTENT_TYPE = 'content-type'; + public const string CONTENT_TYPE = 'content-type'; /** * The key for param 'smtp-host'. * * @var string */ - const SMTP_HOST = 'smtp-host'; + public const string SMTP_HOST = 'smtp-host'; /** * The key for param 'smtp-port'. * * @var string */ - const SMTP_PORT = 'smtp-port'; + public const string SMTP_PORT = 'smtp-port'; /** * The key for param 'smtp-security'. * * @var string */ - const SMTP_SECURITY = 'smtp-security'; + public const string SMTP_SECURITY = 'smtp-security'; /** * The key for param 'smtp-username'. * * @var string */ - const SMTP_USERNAME = 'smtp-username'; + public const string SMTP_USERNAME = 'smtp-username'; /** * The key for param 'smtp-password'. * * @var string */ - const SMTP_PASSWORD = 'smtp-password'; + public const string SMTP_PASSWORD = 'smtp-password'; /** * The key for param 'smtp-auth-mode'. * * @var string */ - const SMTP_AUTH_MODE = 'smtp-auth-mode'; + public const string SMTP_AUTH_MODE = 'smtp-auth-mode'; /** * The key for param 'command'. * * @var string */ - const COMMAND = 'command'; + public const string COMMAND = 'command'; } diff --git a/src/Utils/UrlKeyUtil.php b/src/Utils/UrlKeyUtil.php index 2caeea08..7f9fe984 100644 --- a/src/Utils/UrlKeyUtil.php +++ b/src/Utils/UrlKeyUtil.php @@ -128,7 +128,7 @@ protected function loadUrlRewriteByRequestPathAndStoreId(string $requestPath, in * * @return string The unique URL key */ - protected function doMakeUnique(UrlKeyAwareSubjectInterface $subject, array $entity, string $urlKey, string $urlPath = null) : string + protected function doMakeUnique(UrlKeyAwareSubjectInterface $subject, array $entity, string $urlKey, ?string $urlPath = null) : string { // initialize the store view ID, use the default store view if no store view has diff --git a/symfony/Resources/config/services.xml b/symfony/Resources/config/services.xml index 76e0393d..1cda08bc 100644 --- a/symfony/Resources/config/services.xml +++ b/symfony/Resources/config/services.xml @@ -39,7 +39,7 @@ Monolog\Handler\ErrorLogHandler - + @@ -47,8 +47,8 @@ - - + + diff --git a/tests/unit/RowTraitImpl.php b/tests/unit/RowTraitImpl.php index ae4da7df..cb38c1dc 100644 --- a/tests/unit/RowTraitImpl.php +++ b/tests/unit/RowTraitImpl.php @@ -74,7 +74,7 @@ public function setValue($name, $value) * * @return mixed|null The, almost formatted, value */ - public function getValue($name, $default = null, callable $callback = null) + public function getValue($name, $default = null, ?callable $callback = null) { return parent::getValue($name, $default, $callback); }