Skip to content

Commit

Permalink
Merge branch '2.1'
Browse files Browse the repository at this point in the history
  • Loading branch information
Toflar committed Oct 14, 2024
2 parents b9db9a5 + 08aff9a commit a328724
Show file tree
Hide file tree
Showing 27 changed files with 697 additions and 43 deletions.
6 changes: 4 additions & 2 deletions UPGRADE.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
* The built-in Postmark gateway has been removed.
* The built-in queue gateway has been removed.
* The built-in file gateway has been removed.
* Embedding images in e-mails is not supported anymore.
* Attachment templates are not supported anymore.
* The configurable flattening delimiter in the e-mail notification type has been removed.
* The configurable template in the notification type has been removed.
Expand All @@ -17,7 +16,10 @@
you will have to adjust your workflow. This module has been removed. However, the "Subscribe (Notification Center)"
now has a second forward page setting. You can use this one in order to have a separate confirmation page.
* Tokens will not be validated in the back end anymore. Basically because it's totally okay to write something
like `##something-not-token-related##` in your message, and you should be able to write this.
like `##something_not_token_related##` in your message, and you should be able to write this.
* Tokens will be normalized! In Contao 5, having a token with e.g. a dash (`##my-token##`) is not supported in `{if`
statements anymore. Hence, the Notification Center 2 will normalize this to `##my_token##`. Allowed token names have
the same requirement as PHP variables. All invalid characters will be replaced with a `_`.
* The `filenames` token introduced in 1.7 has been removed. It's a very specific use case which can be provided very easily
as a third party bundle now (not easily possible before and thus part of the core in 1.7).
* The `member_*` tokens in the `lost_password` notification type used to contain the raw database values, they are now
Expand Down
8 changes: 5 additions & 3 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -54,9 +54,11 @@
"require-dev": {
"contao/manager-plugin": "^2.0",
"contao/newsletter-bundle": "^5.0",
"phpunit/phpunit": "^10.0",
"terminal42/contao-build-tools": "dev-main",
"contao/test-case": "^4.9"
"contao/test-case": "^5.3",
"league/flysystem-memory": "^3.25",
"phpunit/phpunit": "^9.6",
"symfony/expression-language": "^5.4 || ^6.0 || ^7.0",
"terminal42/contao-build-tools": "dev-main"
},
"suggest": {
"terminal42/contao-notification-center-pro": "Turn your Notification Center 2 into a pro version and benefit from logs, various testing tools and your own Simple Tokens that can be completely customized with Twig."
Expand Down
1 change: 1 addition & 0 deletions config/listeners.php
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@
->args([
service(NotificationCenter::class),
service(FileUploadNormalizer::class),
service(ConfigLoader::class),
])
;

Expand Down
7 changes: 7 additions & 0 deletions config/services.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
use Symfony\Contracts\Translation\TranslatorInterface;
use Terminal42\NotificationCenterBundle\Backend\AutoSuggester;
use Terminal42\NotificationCenterBundle\BulkyItem\BulkyItemStorage;
use Terminal42\NotificationCenterBundle\BulkyItem\FileItemFactory;
use Terminal42\NotificationCenterBundle\Config\ConfigLoader;
use Terminal42\NotificationCenterBundle\Cron\PruneBulkyItemStorageCron;
use Terminal42\NotificationCenterBundle\DependencyInjection\Terminal42NotificationCenterExtension;
Expand Down Expand Up @@ -59,6 +60,12 @@
])
;

$services->set(FileItemFactory::class)
->args([
service('mime_types')->nullOnInvalid(),
])
;

$services->set(PruneBulkyItemStorageCron::class)
->args([
service(BulkyItemStorage::class),
Expand Down
1 change: 1 addition & 0 deletions contao/dca/tl_form.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
*/
$GLOBALS['TL_DCA']['tl_form']['fields']['nc_notification'] = [
'exclude' => true,
'filter' => true,
'inputType' => 'select',
'eval' => ['includeBlankOption' => true, 'chosen' => true, 'tl_class' => 'clr w50'],
'sql' => ['type' => 'integer', 'default' => 0, 'unsigned' => true],
Expand Down
22 changes: 20 additions & 2 deletions src/BulkyItem/FileItem.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,24 @@
namespace Terminal42\NotificationCenterBundle\BulkyItem;

use Symfony\Component\Filesystem\Filesystem;
use Terminal42\NotificationCenterBundle\Exception\BulkyItem\InvalidFileItemException;

class FileItem implements BulkyItemInterface
{
/**
* @param resource $contents
*
* @throws InvalidFileItemException
*/
private function __construct(
private $contents,
private readonly string $name,
private readonly string $mimeType,
private readonly int $size,
) {
$this->assert('' !== $this->name, 'Name must not be empty');
$this->assert('' !== $this->mimeType, 'Mime type must not be empty');
$this->assert($this->size >= 0, 'File size must not be smaller than 0');
}

public function getName(): string
Expand Down Expand Up @@ -53,24 +59,36 @@ public static function restore($contents, array $meta): BulkyItemInterface
return new self($contents, $meta['name'], $meta['type'], $meta['size']);
}

/**
* @throws InvalidFileItemException
*/
public static function fromPath(string $path, string $name, string $mimeType, int $size): self
{
if (!(new Filesystem())->exists($path)) {
throw new \InvalidArgumentException(\sprintf('The file "%s" does not exist.', $path));
throw new InvalidFileItemException(\sprintf('The file "%s" does not exist.', $path));
}

return new self(fopen($path, 'r'), $name, $mimeType, $size);
}

/**
* @param resource $resource
*
* @throws InvalidFileItemException
*/
public static function fromStream($resource, string $name, string $mimeType, int $size): self
{
if (!\is_resource($resource)) {
throw new \InvalidArgumentException('$contents must be a resource.');
throw new InvalidFileItemException('$contents must be a resource.');
}

return new self($resource, $name, $mimeType, $size);
}

private function assert(bool $condition, string $message): void
{
if (!$condition) {
throw new InvalidFileItemException($message);
}
}
}
44 changes: 44 additions & 0 deletions src/BulkyItem/FileItemFactory.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
<?php

declare(strict_types=1);

namespace Terminal42\NotificationCenterBundle\BulkyItem;

use Contao\CoreBundle\Filesystem\FilesystemItem;
use Contao\CoreBundle\Filesystem\VirtualFilesystemInterface;
use Symfony\Component\Filesystem\Filesystem;
use Symfony\Component\Mime\MimeTypeGuesserInterface;
use Terminal42\NotificationCenterBundle\Exception\BulkyItem\InvalidFileItemException;

class FileItemFactory
{
public function __construct(private readonly MimeTypeGuesserInterface|null $mimeTypeGuesser = null)
{
}

/**
* @throws InvalidFileItemException if the information cannot be fetched automatically (e.g. missing mime type guesser service)
*/
public function createFromLocalPath(string $path): FileItem
{
if (!(new Filesystem())->exists($path)) {
throw new InvalidFileItemException(\sprintf('The file "%s" does not exist.', $path));
}

$name = basename($path);
$mimeType = (string) $this->mimeTypeGuesser?->guessMimeType($path);
$size = (int) filesize($path);

return FileItem::fromPath($path, $name, $mimeType, $size);
}

/**
* @throws InvalidFileItemException
*/
public function createFromVfsFilesystemItem(FilesystemItem $file, VirtualFilesystemInterface $virtualFilesystem): FileItem
{
$stream = $virtualFilesystem->readStream($file->getPath());

return FileItem::fromStream($stream, $file->getName(), $file->getMimeType(), $file->getFileSize());
}
}
5 changes: 5 additions & 0 deletions src/Config/ConfigLoader.php
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,11 @@ public function loadModule(int $id): ModuleConfig|null
return $this->loadConfig($id, 'tl_module', ModuleConfig::class);
}

public function loadForm(int $id): FormConfig|null
{
return $this->loadConfig($id, 'tl_form', FormConfig::class);
}

/**
* @return array<MessageConfig>
*/
Expand Down
9 changes: 9 additions & 0 deletions src/Config/FormConfig.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<?php

declare(strict_types=1);

namespace Terminal42\NotificationCenterBundle\Config;

class FormConfig extends AbstractConfig
{
}
2 changes: 2 additions & 0 deletions src/DependencyInjection/CompilerPass/AbstractGatewayPass.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\DependencyInjection\Reference;
use Terminal42\NotificationCenterBundle\BulkyItem\BulkyItemStorage;
use Terminal42\NotificationCenterBundle\DependencyInjection\Terminal42NotificationCenterExtension;
use Terminal42\NotificationCenterBundle\Gateway\AbstractGateway;
use Terminal42\NotificationCenterBundle\NotificationCenter;
Expand All @@ -20,6 +21,7 @@ public function process(ContainerBuilder $container): void
$taggedServices = $container->findTaggedServiceIds(Terminal42NotificationCenterExtension::GATEWAY_TAG);
$locateableServices = [
AbstractGateway::SERVICE_NAME_NOTIFICATION_CENTER => new Reference(NotificationCenter::class),
AbstractGateway::SERVICE_NAME_BULKY_ITEM_STORAGE => new Reference(BulkyItemStorage::class),
AbstractGateway::SERVICE_NAME_SIMPLE_TOKEN_PARSER => new Reference('contao.string.simple_token_parser', ContainerInterface::NULL_ON_INVALID_REFERENCE),
AbstractGateway::SERVICE_NAME_INSERT_TAG_PARSER => new Reference('contao.insert_tag.parser', ContainerInterface::NULL_ON_INVALID_REFERENCE),
];
Expand Down
11 changes: 10 additions & 1 deletion src/EventListener/ProcessFormDataListener.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,18 @@
use Contao\Form;
use Contao\StringUtil;
use Terminal42\NotificationCenterBundle\BulkyItem\FileItem;
use Terminal42\NotificationCenterBundle\Config\ConfigLoader;
use Terminal42\NotificationCenterBundle\NotificationCenter;
use Terminal42\NotificationCenterBundle\Parcel\Stamp\BulkyItemsStamp;
use Terminal42\NotificationCenterBundle\Parcel\Stamp\FormConfigStamp;

#[AsHook('processFormData')]
class ProcessFormDataListener
{
public function __construct(
private readonly NotificationCenter $notificationCenter,
private readonly FileUploadNormalizer $fileUploadNormalizer,
private readonly ConfigLoader $configLoader,
) {
}

Expand Down Expand Up @@ -76,7 +79,7 @@ public function __invoke(array $submittedData, array $formData, array|null $file
FileItem::fromStream($file['stream'], $file['name'], $file['type'], $file['size']) :
FileItem::fromPath($file['tmp_name'], $file['name'], $file['type'], $file['size']);

$vouchers[] = $this->notificationCenter->getBulkyGoodsStorage()->store($fileItem);
$vouchers[] = $this->notificationCenter->getBulkyItemStorage()->store($fileItem);
}

$tokens['form_'.$k] = implode(',', $vouchers);
Expand All @@ -95,6 +98,12 @@ public function __invoke(array $submittedData, array $formData, array|null $file
$stamps = $stamps->with(new BulkyItemsStamp($bulkyItemVouchers));
}

$formConfig = $this->configLoader->loadForm((int) $form->id);

if (null !== $formConfig) {
$stamps = $stamps->with(new FormConfigStamp($formConfig));
}

$this->notificationCenter->sendNotificationWithStamps((int) $formData['nc_notification'], $stamps);
}
}
9 changes: 9 additions & 0 deletions src/Exception/BulkyItem/InvalidFileItemException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<?php

declare(strict_types=1);

namespace Terminal42\NotificationCenterBundle\Exception\BulkyItem;

class InvalidFileItemException extends \InvalidArgumentException
{
}
32 changes: 27 additions & 5 deletions src/Gateway/AbstractGateway.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
use Contao\CoreBundle\InsertTag\InsertTagParser;
use Contao\CoreBundle\String\SimpleTokenParser;
use Psr\Container\ContainerInterface;
use Terminal42\NotificationCenterBundle\BulkyItem\BulkyItemStorage;
use Terminal42\NotificationCenterBundle\Exception\Parcel\CouldNotDeliverParcelException;
use Terminal42\NotificationCenterBundle\Exception\Parcel\CouldNotSealParcelException;
use Terminal42\NotificationCenterBundle\NotificationCenter;
Expand All @@ -20,6 +21,8 @@ abstract class AbstractGateway implements GatewayInterface
{
public const SERVICE_NAME_NOTIFICATION_CENTER = 'notification_center';

public const SERVICE_NAME_BULKY_ITEM_STORAGE = 'bulky_item_storage';

public const SERVICE_NAME_SIMPLE_TOKEN_PARSER = 'simple_token_parser';

public const SERVICE_NAME_INSERT_TAG_PARSER = 'insert_tag_parser';
Expand Down Expand Up @@ -83,15 +86,23 @@ protected function replaceTokens(Parcel $parcel, string $value): string
return $value;
}

return $this->getSimpleTokenParser()?->parse(
$value,
$parcel->getStamp(TokenCollectionStamp::class)->tokenCollection->forSimpleTokenParser(),
);
if ($simpleTokenParser = $this->getSimpleTokenParser()) {
return $simpleTokenParser->parse(
$value,
$parcel->getStamp(TokenCollectionStamp::class)->tokenCollection->forSimpleTokenParser(),
);
}

return $value;
}

protected function replaceInsertTags(string $value): string
{
return $this->getInsertTagParser()?->replaceInline($value);
if ($insertTagParser = $this->getInsertTagParser()) {
return $insertTagParser->replaceInline($value);
}

return $value;
}

protected function replaceTokensAndInsertTags(Parcel $parcel, string $value): string
Expand Down Expand Up @@ -143,4 +154,15 @@ protected function getNotificationCenter(): NotificationCenter|null

return !$notificationCenter instanceof NotificationCenter ? null : $notificationCenter;
}

protected function getBulkyItemStorage(): BulkyItemStorage|null
{
if (null === $this->container || !$this->container->has(self::SERVICE_NAME_BULKY_ITEM_STORAGE)) {
return null;
}

$bulkyItemStorage = $this->container->get(self::SERVICE_NAME_BULKY_ITEM_STORAGE);

return !$bulkyItemStorage instanceof BulkyItemStorage ? null : $bulkyItemStorage;
}
}
Loading

0 comments on commit a328724

Please sign in to comment.