diff --git a/composer.json b/composer.json index fcfde0401..5e4b8d787 100644 --- a/composer.json +++ b/composer.json @@ -87,64 +87,68 @@ "require": { "php": "^8.1", "ext-json": "*", - "components/font-awesome": "^5.14.0", + "components/font-awesome": "^5.15.0", "composer/composer": "^2.0", - "dflydev/fig-cookies": "^3.0.0", - "doctrine/dbal": "^2.7", - "dragonmantank/cron-expression": "^3.1.0", - "franzl/whoops-middleware": "^2.0.0", - "guzzlehttp/guzzle": "^6.0|^7.4", - "illuminate/bus": "^8.0", - "illuminate/cache": "^8.0", - "illuminate/config": "^8.0", - "illuminate/console": "^8.0", - "illuminate/container": "^8.0", - "illuminate/contracts": "^8.0", - "illuminate/database": "^8.0", - "illuminate/events": "^8.0", - "illuminate/filesystem": "^8.0", - "illuminate/hashing": "^8.0", - "illuminate/mail": "^8.0", - "illuminate/queue": "^8.0", - "illuminate/session": "^8.0", - "illuminate/support": "^8.0", - "illuminate/validation": "^8.0", - "illuminate/view": "^8.0", - "intervention/image": "2.5.* || ^2.6.1", - "jenssegers/agent": "^2.6", - "laminas/laminas-diactoros": "^2.4.1", - "laminas/laminas-httphandlerrunner": "^1.2.0 || ^2.3.0", - "laminas/laminas-stratigility": "^3.2.2", - "league/flysystem": "^1.0.11", + "dflydev/fig-cookies": "^v3.0", + "doctrine/dbal": "^3.6.2", + "dragonmantank/cron-expression": "^v3.3", + "franzl/whoops-middleware": "^2.0", + "guzzlehttp/guzzle": "*", + "illuminate/bus": "^10.0", + "illuminate/cache": "^10.0", + "illuminate/config": "^10.0", + "illuminate/console": "^10.0", + "illuminate/container": "^10.0", + "illuminate/contracts": "^10.0", + "illuminate/database": "^10.0", + "illuminate/events": "^10.0", + "illuminate/filesystem": "^10.0", + "illuminate/hashing": "^10.0", + "illuminate/mail": "^10.0", + "illuminate/queue": "^10.0", + "illuminate/session": "^10.0", + "illuminate/support": "^10.0", + "illuminate/validation": "^10.0", + "illuminate/view": "^10.0", + "intervention/image": "^2.7.2", + "jenssegers/agent": "^v2.6", + "laminas/laminas-diactoros": "^3.0", + "laminas/laminas-httphandlerrunner": "^2.6", + "laminas/laminas-stratigility": "^3.10", + "league/flysystem": "^3.15", + "league/flysystem-memory": "^3.15", "matthiasmullie/minify": "^1.3", - "middlewares/base-path": "^2.0.1", - "middlewares/base-path-router": "^2.0.1", - "middlewares/request-handler": "^2.0.1", - "monolog/monolog": "^1.16.0", - "nesbot/carbon": "^2.0", - "nikic/fast-route": "^0.6", - "psr/http-message": "^1.0", - "psr/http-server-handler": "^1.0", - "psr/http-server-middleware": "^1.0", - "pusher/pusher-php-server": "^2.2", - "s9e/text-formatter": "^2.3.6", - "staudenmeir/eloquent-eager-limit": "^1.0", + "middlewares/base-path": "^v2.1", + "middlewares/base-path-router": "^v2.0.1", + "middlewares/request-handler": "^v2.0.2", + "monolog/monolog": "^3.3", + "nesbot/carbon": "^2.66", + "nikic/fast-route": "^1.3", + "psr/http-message": "^1.1", + "psr/http-server-handler": "^1.0.2", + "psr/http-server-middleware": "^1.0.2", + "pusher/pusher-php-server": "^7.2", + "s9e/text-formatter": "^2.13", + "staudenmeir/eloquent-eager-limit": "^1.8.2", "sycho/json-api": "^0.5.0", "sycho/sourcemap": "^2.0.0", - "symfony/config": "^5.2.2", - "symfony/console": "^5.2.2", - "symfony/event-dispatcher": "^5.2.2", - "symfony/mime": "^5.2.0", - "symfony/polyfill-intl-messageformatter": "^1.22.0", - "symfony/translation": "^5.1.5", - "symfony/yaml": "^5.2.2", + "symfony/config": "^6.3", + "symfony/console": "^6.3", + "symfony/event-dispatcher": "^6.3", + "symfony/http-client": "^6.3", + "symfony/mime": "^6.3", + "symfony/polyfill-intl-messageformatter": "^1.27", + "symfony/postmark-mailer": "^6.3", + "symfony/translation": "^6.3", + "symfony/yaml": "^6.3", "wikimedia/less.php": "^3.0" }, "require-dev": { "mockery/mockery": "^1.4", "phpunit/phpunit": "^9.0", - "phpstan/phpstan": ">=1.8.11 < 1.9.0", - "nunomaduro/larastan": "^1.0" + "phpstan/phpstan": "^1.10.0", + "nunomaduro/larastan": "^2.6", + "symfony/var-dumper": "^6.3" }, "config": { "sort-packages": true diff --git a/extensions/flags/src/Flag.php b/extensions/flags/src/Flag.php index 310b72fa0..1fd01dad7 100644 --- a/extensions/flags/src/Flag.php +++ b/extensions/flags/src/Flag.php @@ -31,7 +31,7 @@ class Flag extends AbstractModel { use ScopeVisibilityTrait; - protected $dates = ['created_at']; + protected $casts = ['created_at' => 'datetime']; public function post(): BelongsTo { diff --git a/extensions/tags/src/Tag.php b/extensions/tags/src/Tag.php index 503bff0be..553f12476 100644 --- a/extensions/tags/src/Tag.php +++ b/extensions/tags/src/Tag.php @@ -54,16 +54,12 @@ class Tag extends AbstractModel protected $table = 'tags'; - /** - * The attributes that should be mutated to dates. - * - * @var array - */ - protected $dates = ['last_posted_at', 'created_at', 'updated_at']; - protected $casts = [ 'is_hidden' => 'bool', - 'is_restricted' => 'bool' + 'is_restricted' => 'bool', + 'last_posted_at' => 'datetime', + 'created_at' => 'datetime', + 'updated_at' => 'datetime', ]; public static function boot() diff --git a/extensions/tags/src/TagState.php b/extensions/tags/src/TagState.php index f020826d5..c17c0f6b5 100644 --- a/extensions/tags/src/TagState.php +++ b/extensions/tags/src/TagState.php @@ -29,7 +29,7 @@ class TagState extends AbstractModel protected $table = 'tag_user'; - protected $dates = ['marked_as_read_at']; + protected $casts = ['marked_as_read_at' => 'datetime']; public function tag(): BelongsTo { diff --git a/framework/core/composer.json b/framework/core/composer.json index 20ea96ac1..3babc4d8e 100644 --- a/framework/core/composer.json +++ b/framework/core/composer.json @@ -37,59 +37,66 @@ }, "require": { "php": "^8.1", - "components/font-awesome": "^5.14.0", - "dflydev/fig-cookies": "^3.0.0", - "doctrine/dbal": "^2.7", - "dragonmantank/cron-expression": "^3.1.0", - "franzl/whoops-middleware": "^2.0.0", - "guzzlehttp/guzzle": "^6.0|^7.4", - "illuminate/bus": "^8.0", - "illuminate/cache": "^8.0", - "illuminate/config": "^8.0", - "illuminate/console": "^8.0", - "illuminate/container": "^8.0", - "illuminate/contracts": "^8.0", - "illuminate/database": "^8.0", - "illuminate/events": "^8.0", - "illuminate/filesystem": "^8.0", - "illuminate/hashing": "^8.0", - "illuminate/mail": "^8.0", - "illuminate/queue": "^8.0", - "illuminate/session": "^8.0", - "illuminate/support": "^8.0", - "illuminate/validation": "^8.0", - "illuminate/view": "^8.0", - "intervention/image": "2.5.* || ^2.6.1", - "jenssegers/agent": "^2.6", - "laminas/laminas-diactoros": "^2.4.1", - "laminas/laminas-httphandlerrunner": "^1.2.0 || ^2.3.0", - "laminas/laminas-stratigility": "^3.2.2", - "league/flysystem": "^1.0.11", - "matthiasmullie/minify": "^1.3", - "middlewares/base-path": "^2.0.1", - "middlewares/base-path-router": "^2.0.1", - "middlewares/request-handler": "^2.0.1", - "monolog/monolog": "^1.16.0", + "components/font-awesome": "^5.15.0", + "dflydev/fig-cookies": "^v3.0", + "doctrine/dbal": "^3.6", + "dragonmantank/cron-expression": "*", + "franzl/whoops-middleware": "V2.0", + "guzzlehttp/guzzle": "^7.7", + "illuminate/bus": "^10.0", + "illuminate/cache": "^10.0", + "illuminate/config": "^10.0", + "illuminate/console": "^10.0", + "illuminate/container": "^10.0", + "illuminate/contracts": "^10.0", + "illuminate/database": "^10.0", + "illuminate/events": "^10.0", + "illuminate/filesystem": "^10.0", + "illuminate/hashing": "^10.0", + "illuminate/mail": "^10.0", + "illuminate/queue": "^10.0", + "illuminate/session": "^10.0", + "illuminate/support": "^10.0", + "illuminate/validation": "^10.0", + "illuminate/view": "^10.0", + "intervention/image": "^2.7.2", + "jenssegers/agent": "^v2.6.4", + "laminas/laminas-diactoros": "^3.0", + "laminas/laminas-httphandlerrunner": "^2.6.1", + "laminas/laminas-stratigility": "^3.10", + "league/flysystem": "^3.15", + "league/flysystem-memory": "^3.15", + "matthiasmullie/minify": "^1.3.70", + "middlewares/base-path": "^v2.1.0", + "middlewares/base-path-router": "^v2.0.1", + "middlewares/request-handler": "^v2.0.2", + "monolog/monolog": "^3.0", "nesbot/carbon": "^2.0", - "nikic/fast-route": "^0.6", - "psr/http-message": "^1.0", - "psr/http-server-handler": "^1.0", - "psr/http-server-middleware": "^1.0", - "s9e/text-formatter": "^2.3.6", - "staudenmeir/eloquent-eager-limit": "^1.0", + "nikic/fast-route": "^v1.3", + "psr/http-message": "^1.1", + "psr/http-server-handler": "^1.0.2", + "psr/http-server-middleware": "^1.0.2", + "s9e/text-formatter": "^2.13", + "staudenmeir/eloquent-eager-limit": "^1.8.2", "sycho/json-api": "^0.5.0", "sycho/sourcemap": "^2.0.0", - "symfony/config": "^5.2.2", - "symfony/console": "^5.2.2", - "symfony/event-dispatcher": "^5.2.2", - "symfony/mime": "^5.2.0", - "symfony/polyfill-intl-messageformatter": "^1.22.0", - "symfony/translation": "^5.1.5", - "symfony/yaml": "^5.2.2", - "wikimedia/less.php": "^3.2" + "symfony/config": "^6.3", + "symfony/console": "^6.3", + "symfony/event-dispatcher": "^6.3", + "symfony/http-client": "^6.3", + "symfony/mailer": "^6.3", + "symfony/mailgun-mailer": "^6.3", + "symfony/mime": "^6.3", + "symfony/polyfill-intl-messageformatter": "^1.27", + "symfony/postmark-mailer": "^6.3", + "symfony/translation": "^6.3", + "symfony/translation-contracts": "^2.5", + "symfony/yaml": "^6.3", + "wikimedia/less.php": "^3.0" }, "require-dev": { - "flarum/testing": "^2.0" + "flarum/testing": "^2.0", + "symfony/var-dumper": "^6.3" }, "autoload": { "psr-4": { diff --git a/framework/core/src/Api/ApiKey.php b/framework/core/src/Api/ApiKey.php index 9dcaaabbc..bd8f8c45e 100644 --- a/framework/core/src/Api/ApiKey.php +++ b/framework/core/src/Api/ApiKey.php @@ -27,7 +27,7 @@ use Illuminate\Support\Str; */ class ApiKey extends AbstractModel { - protected $dates = ['last_activity_at']; + protected $casts = ['last_activity_at' => 'datetime']; public static function generate(): static { @@ -38,7 +38,7 @@ class ApiKey extends AbstractModel return $key; } - public function touch(): bool + public function touch($attribute = null): bool { $this->last_activity_at = Carbon::now(); diff --git a/framework/core/src/Api/Controller/CreateTokenController.php b/framework/core/src/Api/Controller/CreateTokenController.php index adb7049d4..5d64d972d 100644 --- a/framework/core/src/Api/Controller/CreateTokenController.php +++ b/framework/core/src/Api/Controller/CreateTokenController.php @@ -57,7 +57,7 @@ class CreateTokenController implements RequestHandlerInterface } // We do a first update here to log the IP/agent of the token creator, even if the token is never used afterwards - $token->touch($request); + $token->touch(request: $request); return new JsonResponse([ 'token' => $token->token, diff --git a/framework/core/src/Database/ScopeVisibilityTrait.php b/framework/core/src/Database/ScopeVisibilityTrait.php index 21e9cd2d7..1cbfc3346 100644 --- a/framework/core/src/Database/ScopeVisibilityTrait.php +++ b/framework/core/src/Database/ScopeVisibilityTrait.php @@ -18,7 +18,7 @@ trait ScopeVisibilityTrait /** * @todo: define clear scoper interfaces. * - * @var array> + * @var array> */ protected static array $visibilityScopers = []; diff --git a/framework/core/src/Discussion/Discussion.php b/framework/core/src/Discussion/Discussion.php index ef7f0082b..313472451 100644 --- a/framework/core/src/Discussion/Discussion.php +++ b/framework/core/src/Discussion/Discussion.php @@ -69,20 +69,16 @@ class Discussion extends AbstractModel */ protected array $modifiedPosts = []; - /** - * The attributes that should be mutated to dates. - * - * @var array - */ - protected $dates = ['created_at', 'last_posted_at', 'hidden_at']; - /** * The attributes that should be cast to native types. * * @var array */ protected $casts = [ - 'is_private' => 'boolean' + 'is_private' => 'boolean', + 'created_at' => 'datetime', + 'last_posted_at' => 'datetime', + 'hidden_at' => 'datetime', ]; /** diff --git a/framework/core/src/Discussion/UserState.php b/framework/core/src/Discussion/UserState.php index 1dd7c52c9..9369a7e9d 100644 --- a/framework/core/src/Discussion/UserState.php +++ b/framework/core/src/Discussion/UserState.php @@ -42,7 +42,7 @@ class UserState extends AbstractModel * * @var array */ - protected $dates = ['last_read_at']; + protected $casts = ['last_read_at' => 'datetime']; /** * The attributes that are mass assignable. diff --git a/framework/core/src/Filesystem/FilesystemServiceProvider.php b/framework/core/src/Filesystem/FilesystemServiceProvider.php index cbba4fb66..633fe64f3 100644 --- a/framework/core/src/Filesystem/FilesystemServiceProvider.php +++ b/framework/core/src/Filesystem/FilesystemServiceProvider.php @@ -26,7 +26,7 @@ class FilesystemServiceProvider extends AbstractServiceProvider public function register(): void { $this->container->singleton('files', function () { - return new Filesystem; + return new Filesystem(); }); $this->container->singleton('flarum.filesystem.disks', function () { diff --git a/framework/core/src/Forum/ValidateCustomLess.php b/framework/core/src/Forum/ValidateCustomLess.php index 266440b45..e397a13d9 100644 --- a/framework/core/src/Forum/ValidateCustomLess.php +++ b/framework/core/src/Forum/ValidateCustomLess.php @@ -18,8 +18,8 @@ use Flarum\Settings\OverrideSettingsRepository; use Flarum\Settings\SettingsRepositoryInterface; use Illuminate\Contracts\Container\Container; use Illuminate\Filesystem\FilesystemAdapter; -use League\Flysystem\Adapter\NullAdapter; use League\Flysystem\Filesystem; +use League\Flysystem\InMemory\InMemoryFilesystemAdapter; use Less_Exception_Parser; use Symfony\Contracts\Translation\TranslatorInterface; @@ -68,7 +68,9 @@ class ValidateCustomLess ); $assetsDir = $this->assets->getAssetsDir(); - $this->assets->setAssetsDir(new FilesystemAdapter(new Filesystem(new NullAdapter))); + + $adapter = new InMemoryFilesystemAdapter(); + $this->assets->setAssetsDir(new FilesystemAdapter(new Filesystem($adapter), $adapter)); try { $this->assets->makeCss()->commit(); diff --git a/framework/core/src/Foundation/Container.php b/framework/core/src/Foundation/Container.php new file mode 100644 index 000000000..590ea1b89 --- /dev/null +++ b/framework/core/src/Foundation/Container.php @@ -0,0 +1,21 @@ +paths); $container->instance('env', 'production'); @@ -165,7 +165,7 @@ class InstalledSite implements SiteInterface protected function registerLogger(Container $container): void { $logPath = $this->paths->storage.'/logs/flarum.log'; - $logLevel = $this->config->inDebugMode() ? Logger::DEBUG : Logger::INFO; + $logLevel = $this->config->inDebugMode() ? Level::Debug : Level::Info; $handler = new RotatingFileHandler($logPath, 0, $logLevel); $handler->setFormatter(new LineFormatter(null, null, true, true)); diff --git a/framework/core/src/Group/Group.php b/framework/core/src/Group/Group.php index 927606ae4..8a809f22c 100644 --- a/framework/core/src/Group/Group.php +++ b/framework/core/src/Group/Group.php @@ -44,7 +44,10 @@ class Group extends AbstractModel * * @var array */ - protected $dates = ['created_at', 'updated_at']; + protected $casts = [ + 'created_at' => 'datetime', + 'updated_at' => 'datetime', + ]; public static function boot() { diff --git a/framework/core/src/Group/Permission.php b/framework/core/src/Group/Permission.php index 5ddb3e854..28ebd8768 100644 --- a/framework/core/src/Group/Permission.php +++ b/framework/core/src/Group/Permission.php @@ -26,7 +26,7 @@ class Permission extends AbstractModel * * @var array */ - protected $dates = ['created_at']; + protected $casts = ['created_at' => 'datetime']; public function group(): BelongsTo { diff --git a/framework/core/src/Http/AccessToken.php b/framework/core/src/Http/AccessToken.php index 25137b148..faf492806 100644 --- a/framework/core/src/Http/AccessToken.php +++ b/framework/core/src/Http/AccessToken.php @@ -37,9 +37,9 @@ class AccessToken extends AbstractModel protected $table = 'access_tokens'; - protected $dates = [ - 'created_at', - 'last_activity_at', + protected $casts = [ + 'created_at' => 'datetime', + 'last_activity_at' => 'datetime', ]; /** @@ -94,7 +94,7 @@ class AccessToken extends AbstractModel * Update the time of last usage of a token. * If a request object is provided, the IP address and User Agent will also be logged. */ - public function touch(?ServerRequestInterface $request = null): bool + public function touch($attribute = null, ServerRequestInterface $request = null): bool { $now = Carbon::now(); diff --git a/framework/core/src/Http/Middleware/AuthenticateWithHeader.php b/framework/core/src/Http/Middleware/AuthenticateWithHeader.php index f505aeff3..27b346df5 100644 --- a/framework/core/src/Http/Middleware/AuthenticateWithHeader.php +++ b/framework/core/src/Http/Middleware/AuthenticateWithHeader.php @@ -41,7 +41,7 @@ class AuthenticateWithHeader implements Middleware $request = $request->withAttribute('apiKey', $key); $request = $request->withAttribute('bypassThrottling', true); } elseif ($token = AccessToken::findValid($id)) { - $token->touch($request); + $token->touch(request: $request); $actor = $token->user; } diff --git a/framework/core/src/Http/Middleware/AuthenticateWithSession.php b/framework/core/src/Http/Middleware/AuthenticateWithSession.php index 3e98c74a0..2af77257c 100644 --- a/framework/core/src/Http/Middleware/AuthenticateWithSession.php +++ b/framework/core/src/Http/Middleware/AuthenticateWithSession.php @@ -41,7 +41,7 @@ class AuthenticateWithSession implements Middleware $actor = $token->user; $actor->updateLastSeen()->save(); - $token->touch($request); + $token->touch(request: $request); return $actor; } diff --git a/framework/core/src/Http/Middleware/RememberFromCookie.php b/framework/core/src/Http/Middleware/RememberFromCookie.php index 3c9620372..c5d8315f6 100644 --- a/framework/core/src/Http/Middleware/RememberFromCookie.php +++ b/framework/core/src/Http/Middleware/RememberFromCookie.php @@ -33,7 +33,7 @@ class RememberFromCookie implements Middleware $token = AccessToken::findValid($id); if ($token && $token instanceof RememberAccessToken) { - $token->touch($request); + $token->touch(request: $request); /** @var \Illuminate\Contracts\Session\Session $session */ $session = $request->getAttribute('session'); diff --git a/framework/core/src/Locale/PrefixedYamlFileLoader.php b/framework/core/src/Locale/PrefixedYamlFileLoader.php index a320fe912..20f69a4d4 100644 --- a/framework/core/src/Locale/PrefixedYamlFileLoader.php +++ b/framework/core/src/Locale/PrefixedYamlFileLoader.php @@ -14,7 +14,7 @@ use Symfony\Component\Translation\MessageCatalogue; class PrefixedYamlFileLoader extends YamlFileLoader { - public function load($resource, $locale, $domain = 'messages'): MessageCatalogue + public function load(mixed $resource, $locale, $domain = 'messages'): MessageCatalogue { $catalogue = parent::load($resource['file'], $locale, $domain); diff --git a/framework/core/src/Locale/Translator.php b/framework/core/src/Locale/Translator.php index a89403843..11948c49f 100644 --- a/framework/core/src/Locale/Translator.php +++ b/framework/core/src/Locale/Translator.php @@ -27,7 +27,7 @@ class Translator extends BaseTranslator implements TranslatorInterface return $this->trans($key, $replace, null, $locale); } - public function getCatalogue($locale = null): MessageCatalogueInterface + public function getCatalogue(?string $locale = null): MessageCatalogueInterface { if (null === $locale) { $locale = $this->getLocale(); @@ -73,7 +73,7 @@ class Translator extends BaseTranslator implements TranslatorInterface return $translation; } - public function setLocale($locale) + public function setLocale($locale): void { parent::setLocale($locale); } diff --git a/framework/core/src/Mail/DriverInterface.php b/framework/core/src/Mail/DriverInterface.php index 17fa26aa9..19a37d073 100644 --- a/framework/core/src/Mail/DriverInterface.php +++ b/framework/core/src/Mail/DriverInterface.php @@ -12,7 +12,7 @@ namespace Flarum\Mail; use Flarum\Settings\SettingsRepositoryInterface; use Illuminate\Contracts\Validation\Factory; use Illuminate\Support\MessageBag; -use Swift_Transport; +use Symfony\Component\Mailer\Transport\TransportInterface; /** * An interface for a mail service. @@ -56,5 +56,5 @@ interface DriverInterface /** * Build a mail transport based on Flarum's current settings. */ - public function buildTransport(SettingsRepositoryInterface $settings): Swift_Transport; + public function buildTransport(SettingsRepositoryInterface $settings): TransportInterface; } diff --git a/framework/core/src/Mail/FlarumLogTransport.php b/framework/core/src/Mail/FlarumLogTransport.php index 4779e8004..22c5b29ab 100644 --- a/framework/core/src/Mail/FlarumLogTransport.php +++ b/framework/core/src/Mail/FlarumLogTransport.php @@ -10,24 +10,26 @@ namespace Flarum\Mail; use Illuminate\Mail\Transport\LogTransport; -use Swift_Mime_SimpleMessage; +use Symfony\Component\Mailer\Envelope; +use Symfony\Component\Mailer\SentMessage; +use Symfony\Component\Mime\RawMessage; class FlarumLogTransport extends LogTransport { /** * {@inheritdoc} - * - * @return int */ - public function send(Swift_Mime_SimpleMessage $message, &$failedRecipients = null) + public function send(RawMessage $message, Envelope $envelope = null): ?SentMessage { - $this->beforeSendPerformed($message); + $string = $message->toString(); + + if (str_contains($string, 'Content-Transfer-Encoding: quoted-printable')) { + $string = quoted_printable_decode($string); + } // Overriden to use info, so the log driver works in non-debug mode. - $this->logger->info($this->getMimeEntityString($message)); + $this->logger->info($string); - $this->sendPerformed($message); - - return $this->numberOfRecipients($message); + return new SentMessage($message, $envelope ?? Envelope::create($message)); } } diff --git a/framework/core/src/Mail/LogDriver.php b/framework/core/src/Mail/LogDriver.php index 45dbd9b3d..854773890 100644 --- a/framework/core/src/Mail/LogDriver.php +++ b/framework/core/src/Mail/LogDriver.php @@ -13,7 +13,7 @@ use Flarum\Settings\SettingsRepositoryInterface; use Illuminate\Contracts\Validation\Factory; use Illuminate\Support\MessageBag; use Psr\Log\LoggerInterface; -use Swift_Transport; +use Symfony\Component\Mailer\Transport\TransportInterface; class LogDriver implements DriverInterface { @@ -37,7 +37,7 @@ class LogDriver implements DriverInterface return false; } - public function buildTransport(SettingsRepositoryInterface $settings): Swift_Transport + public function buildTransport(SettingsRepositoryInterface $settings): TransportInterface { return new FlarumLogTransport($this->logger); } diff --git a/framework/core/src/Mail/MailServiceProvider.php b/framework/core/src/Mail/MailServiceProvider.php index 811ce2573..3244a0685 100644 --- a/framework/core/src/Mail/MailServiceProvider.php +++ b/framework/core/src/Mail/MailServiceProvider.php @@ -12,10 +12,11 @@ namespace Flarum\Mail; use Flarum\Foundation\AbstractServiceProvider; use Flarum\Settings\SettingsRepositoryInterface; use Illuminate\Contracts\Container\Container; +use Illuminate\Contracts\Mail\Mailer as MailerContract; use Illuminate\Contracts\Validation\Factory; use Illuminate\Mail\Mailer; use Illuminate\Support\Arr; -use Swift_Mailer; +use Symfony\Component\Mailer\Transport\TransportInterface; class MailServiceProvider extends AbstractServiceProvider { @@ -54,19 +55,17 @@ class MailServiceProvider extends AbstractServiceProvider : $container->make(NullDriver::class); }); - $this->container->singleton('swift.mailer', function (Container $container) { - return new Swift_Mailer( - $container->make('mail.driver')->buildTransport( - $container->make(SettingsRepositoryInterface::class) - ) + $this->container->singleton('symfony.mailer.transport', function (Container $container): TransportInterface { + return $container->make('mail.driver')->buildTransport( + $container->make(SettingsRepositoryInterface::class) ); }); - $this->container->singleton('mailer', function (Container $container) { + $this->container->singleton('mailer', function (Container $container): MailerContract { $mailer = new Mailer( 'flarum', $container['view'], - $container['swift.mailer'], + $container['symfony.mailer.transport'], $container['events'] ); @@ -79,5 +78,7 @@ class MailServiceProvider extends AbstractServiceProvider return $mailer; }); + + $this->container->alias('mailer', MailerContract::class); } } diff --git a/framework/core/src/Mail/MailgunDriver.php b/framework/core/src/Mail/MailgunDriver.php index 1d28a05be..16a57a07f 100644 --- a/framework/core/src/Mail/MailgunDriver.php +++ b/framework/core/src/Mail/MailgunDriver.php @@ -10,11 +10,11 @@ namespace Flarum\Mail; use Flarum\Settings\SettingsRepositoryInterface; -use GuzzleHttp\Client; use Illuminate\Contracts\Validation\Factory; -use Illuminate\Mail\Transport\MailgunTransport; use Illuminate\Support\MessageBag; -use Swift_Transport; +use Symfony\Component\Mailer\Bridge\Mailgun\Transport\MailgunTransportFactory; +use Symfony\Component\Mailer\Transport\Dsn; +use Symfony\Component\Mailer\Transport\TransportInterface; class MailgunDriver implements DriverInterface { @@ -44,13 +44,15 @@ class MailgunDriver implements DriverInterface return true; } - public function buildTransport(SettingsRepositoryInterface $settings): Swift_Transport + public function buildTransport(SettingsRepositoryInterface $settings): TransportInterface { - return new MailgunTransport( - new Client(['connect_timeout' => 60]), + $factory = new MailgunTransportFactory(); + + return $factory->create(new Dsn( + 'mailgun+api', + $settings->get('mail_mailgun_region'), $settings->get('mail_mailgun_secret'), - $settings->get('mail_mailgun_domain'), - $settings->get('mail_mailgun_region') - ); + $settings->get('mail_mailgun_domain') + )); } } diff --git a/framework/core/src/Mail/NullDriver.php b/framework/core/src/Mail/NullDriver.php index 55e651a4a..977b3859a 100644 --- a/framework/core/src/Mail/NullDriver.php +++ b/framework/core/src/Mail/NullDriver.php @@ -12,8 +12,8 @@ namespace Flarum\Mail; use Flarum\Settings\SettingsRepositoryInterface; use Illuminate\Contracts\Validation\Factory; use Illuminate\Support\MessageBag; -use Swift_NullTransport; -use Swift_Transport; +use Symfony\Component\Mailer\Transport\NullTransport; +use Symfony\Component\Mailer\Transport\TransportInterface; class NullDriver implements DriverInterface { @@ -32,8 +32,8 @@ class NullDriver implements DriverInterface return false; } - public function buildTransport(SettingsRepositoryInterface $settings): Swift_Transport + public function buildTransport(SettingsRepositoryInterface $settings): TransportInterface { - return new Swift_NullTransport(); + return new NullTransport(); } } diff --git a/framework/core/src/Mail/SendmailDriver.php b/framework/core/src/Mail/SendmailDriver.php index 7a1f4e735..c07d227aa 100644 --- a/framework/core/src/Mail/SendmailDriver.php +++ b/framework/core/src/Mail/SendmailDriver.php @@ -12,8 +12,9 @@ namespace Flarum\Mail; use Flarum\Settings\SettingsRepositoryInterface; use Illuminate\Contracts\Validation\Factory; use Illuminate\Support\MessageBag; -use Swift_SendmailTransport; -use Swift_Transport; +use Symfony\Component\Mailer\Transport\Dsn; +use Symfony\Component\Mailer\Transport\SendmailTransportFactory; +use Symfony\Component\Mailer\Transport\TransportInterface; class SendmailDriver implements DriverInterface { @@ -32,8 +33,8 @@ class SendmailDriver implements DriverInterface return true; } - public function buildTransport(SettingsRepositoryInterface $settings): Swift_Transport + public function buildTransport(SettingsRepositoryInterface $settings): TransportInterface { - return new Swift_SendmailTransport; + return (new SendmailTransportFactory())->create(new Dsn('', 'sendmail')); } } diff --git a/framework/core/src/Mail/SmtpDriver.php b/framework/core/src/Mail/SmtpDriver.php index 5cca7adde..97727ed6d 100644 --- a/framework/core/src/Mail/SmtpDriver.php +++ b/framework/core/src/Mail/SmtpDriver.php @@ -12,11 +12,17 @@ namespace Flarum\Mail; use Flarum\Settings\SettingsRepositoryInterface; use Illuminate\Contracts\Validation\Factory; use Illuminate\Support\MessageBag; -use Swift_SmtpTransport; -use Swift_Transport; +use Symfony\Component\Mailer\Transport\Dsn; +use Symfony\Component\Mailer\Transport\Smtp\EsmtpTransportFactory; +use Symfony\Component\Mailer\Transport\TransportInterface; class SmtpDriver implements DriverInterface { + public function __construct( + protected EsmtpTransportFactory $factory + ) { + } + public function availableSettings(): array { return [ @@ -44,17 +50,14 @@ class SmtpDriver implements DriverInterface return true; } - public function buildTransport(SettingsRepositoryInterface $settings): Swift_Transport + public function buildTransport(SettingsRepositoryInterface $settings): TransportInterface { - $transport = new Swift_SmtpTransport( + return $this->factory->create(new Dsn( + $settings->get('mail_encryption') === 'tls' ? 'smtps' : '', $settings->get('mail_host'), - $settings->get('mail_port'), - $settings->get('mail_encryption') - ); - - $transport->setUsername($settings->get('mail_username')); - $transport->setPassword($settings->get('mail_password')); - - return $transport; + $settings->get('mail_username'), + $settings->get('mail_password'), + $settings->get('mail_port') + )); } } diff --git a/framework/core/src/Notification/Notification.php b/framework/core/src/Notification/Notification.php index 62e7ccfae..b3ba44d5d 100644 --- a/framework/core/src/Notification/Notification.php +++ b/framework/core/src/Notification/Notification.php @@ -52,7 +52,7 @@ class Notification extends AbstractModel * * @var array */ - protected $dates = ['created_at', 'read_at']; + protected $casts = ['created_at' => 'datetime', 'read_at' => 'datetime']; /** * A map of notification types and the model classes to use for their diff --git a/framework/core/src/Post/Post.php b/framework/core/src/Post/Post.php index 18f5448c9..4b875fbe0 100644 --- a/framework/core/src/Post/Post.php +++ b/framework/core/src/Post/Post.php @@ -48,20 +48,16 @@ class Post extends AbstractModel protected $table = 'posts'; - /** - * The attributes that should be mutated to dates. - * - * @var array - */ - protected $dates = ['created_at', 'edited_at', 'hidden_at']; - /** * The attributes that should be cast to native types. * * @var array */ protected $casts = [ - 'is_private' => 'boolean' + 'is_private' => 'boolean', + 'created_at' => 'datetime', + 'edited_at' => 'datetime', + 'hidden_at' => 'datetime' ]; /** diff --git a/framework/core/src/Queue/ExceptionHandler.php b/framework/core/src/Queue/ExceptionHandler.php index 7bb575563..973357834 100644 --- a/framework/core/src/Queue/ExceptionHandler.php +++ b/framework/core/src/Queue/ExceptionHandler.php @@ -9,7 +9,6 @@ namespace Flarum\Queue; -use Exception; use Illuminate\Contracts\Debug\ExceptionHandler as ExceptionHandling; use Psr\Log\LoggerInterface; use Throwable; diff --git a/framework/core/src/User/EmailToken.php b/framework/core/src/User/EmailToken.php index d123ffa94..6fda5433a 100644 --- a/framework/core/src/User/EmailToken.php +++ b/framework/core/src/User/EmailToken.php @@ -29,7 +29,7 @@ class EmailToken extends AbstractModel * * @var array */ - protected $dates = ['created_at']; + protected $casts = ['created_at' => 'datetime']; /** * Use a custom primary key for this model. diff --git a/framework/core/src/User/LoginProvider.php b/framework/core/src/User/LoginProvider.php index 91074284e..d463b9de5 100644 --- a/framework/core/src/User/LoginProvider.php +++ b/framework/core/src/User/LoginProvider.php @@ -23,7 +23,10 @@ use Illuminate\Database\Eloquent\Relations\BelongsTo; */ class LoginProvider extends AbstractModel { - protected $dates = ['created_at', 'last_login_at']; + protected $casts = [ + 'created_at' => 'datetime', + 'last_login_at' => 'datetime', + ]; public $timestamps = true; diff --git a/framework/core/src/User/PasswordToken.php b/framework/core/src/User/PasswordToken.php index c79527eb1..4806cb3c1 100644 --- a/framework/core/src/User/PasswordToken.php +++ b/framework/core/src/User/PasswordToken.php @@ -26,7 +26,7 @@ class PasswordToken extends AbstractModel * * @var array */ - protected $dates = ['created_at']; + protected $casts = ['created_at' => 'datetime']; /** * Use a custom primary key for this model. diff --git a/framework/core/src/User/RegistrationToken.php b/framework/core/src/User/RegistrationToken.php index 0f7ed3067..069ad0a06 100644 --- a/framework/core/src/User/RegistrationToken.php +++ b/framework/core/src/User/RegistrationToken.php @@ -27,16 +27,10 @@ use Illuminate\Support\Str; */ class RegistrationToken extends AbstractModel { - /** - * The attributes that should be mutated to dates. - * - * @var array - */ - protected $dates = ['created_at']; - protected $casts = [ 'user_attributes' => 'array', - 'payload' => 'array' + 'payload' => 'array', + 'created_at' => 'datetime' ]; /** diff --git a/framework/core/src/User/User.php b/framework/core/src/User/User.php index 327ee60a5..e0a92f2a2 100644 --- a/framework/core/src/User/User.php +++ b/framework/core/src/User/User.php @@ -62,16 +62,11 @@ class User extends AbstractModel use ScopeVisibilityTrait; use HasEagerLimit; - /** - * The attributes that should be mutated to dates. - * - * @var array - */ - protected $dates = [ - 'joined_at', - 'last_seen_at', - 'marked_all_as_read_at', - 'read_notifications_at' + protected $casts = [ + 'joined_at' => 'datetime', + 'last_seen_at' => 'datetime', + 'marked_all_as_read_at' => 'datetime', + 'read_notifications_at' => 'datetime', ]; /** diff --git a/framework/core/src/helpers.php b/framework/core/src/helpers.php index b97f16616..51aa9acb8 100644 --- a/framework/core/src/helpers.php +++ b/framework/core/src/helpers.php @@ -7,8 +7,8 @@ * LICENSE file that was distributed with this source code. */ +use Flarum\Foundation\Container; use Flarum\Foundation\Paths; -use Illuminate\Container\Container; use Illuminate\Contracts\Config\Repository; if (! function_exists('resolve')) { diff --git a/framework/core/tests/integration/api/access_tokens/AccessTokenLifecycleTest.php b/framework/core/tests/integration/api/access_tokens/AccessTokenLifecycleTest.php index 129b1b100..f2ddeef21 100644 --- a/framework/core/tests/integration/api/access_tokens/AccessTokenLifecycleTest.php +++ b/framework/core/tests/integration/api/access_tokens/AccessTokenLifecycleTest.php @@ -113,7 +113,7 @@ class AccessTokenLifecycleTest extends TestCase /** @var AccessToken $token */ $token = AccessToken::whereToken('a')->firstOrFail(); - $token->touch((new ServerRequest([ + $token->touch(request: (new ServerRequest([ 'HTTP_USER_AGENT' => 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/47.0.2526.111 Safari/537.36', ]))->withAttribute('ipAddress', '8.8.8.8')); @@ -132,7 +132,7 @@ class AccessTokenLifecycleTest extends TestCase /** @var AccessToken $token */ $token = AccessToken::whereToken('a')->firstOrFail(); - $token->touch(new ServerRequest([ + $token->touch(request: new ServerRequest([ 'HTTP_USER_AGENT' => str_repeat('a', 500), ])); diff --git a/framework/core/tests/integration/api/users/CreateTest.php b/framework/core/tests/integration/api/users/CreateTest.php index 8c0429291..92789763d 100644 --- a/framework/core/tests/integration/api/users/CreateTest.php +++ b/framework/core/tests/integration/api/users/CreateTest.php @@ -258,7 +258,7 @@ class CreateTest extends TestCase 'username' => 'test', 'email' => 'test@machine.local', 'is_email_confirmed' => 1, - 'avatar_url' => 'https://192.168.0.1/image.png' + 'avatar_url' => 'https://i_do_not_exist.flarum.org/image.png' ], []); $regTokens[] = RegistrationToken::generate('flarum', '1', [ diff --git a/framework/core/tests/integration/extenders/FilesystemTest.php b/framework/core/tests/integration/extenders/FilesystemTest.php index 3edcaf4bf..1d146a6a5 100644 --- a/framework/core/tests/integration/extenders/FilesystemTest.php +++ b/framework/core/tests/integration/extenders/FilesystemTest.php @@ -20,9 +20,8 @@ use Flarum\Testing\integration\TestCase; use Illuminate\Contracts\Filesystem\Cloud; use Illuminate\Filesystem\FilesystemAdapter; use InvalidArgumentException; -use League\Flysystem\Adapter\Local; -use League\Flysystem\Adapter\NullAdapter; -use League\Flysystem\Filesystem as LeagueFilesystem; +use League\Flysystem\InMemory\InMemoryFilesystemAdapter; +use League\Flysystem\Local\LocalFilesystemAdapter; class FilesystemTest extends TestCase { @@ -49,9 +48,10 @@ class FilesystemTest extends TestCase ]; })); + /** @var FilesystemAdapter $uploadsDisk */ $uploadsDisk = $this->app()->getContainer()->make('filesystem')->disk('flarum-uploads'); - $this->assertEquals(get_class($uploadsDisk->getDriver()->getAdapter()), Local::class); + $this->assertEquals(get_class($uploadsDisk->getAdapter()), LocalFilesystemAdapter::class); } /** @@ -61,9 +61,10 @@ class FilesystemTest extends TestCase { $this->extend((new Extend\Filesystem)->disk('flarum-uploads', UploadsDisk::class)); + /** @var FilesystemAdapter $uploadsDisk */ $uploadsDisk = $this->app()->getContainer()->make('filesystem')->disk('flarum-uploads'); - $this->assertEquals(get_class($uploadsDisk->getDriver()->getAdapter()), Local::class); + $this->assertEquals(get_class($uploadsDisk->getAdapter()), LocalFilesystemAdapter::class); } /** @@ -73,9 +74,10 @@ class FilesystemTest extends TestCase { $this->app()->getContainer()->make(SettingsRepositoryInterface::class)->set('disk_driver.flarum-assets', 'nonexistent_driver'); + /** @var FilesystemAdapter $assetsDisk */ $assetsDisk = $this->app()->getContainer()->make('filesystem')->disk('flarum-assets'); - $this->assertEquals(get_class($assetsDisk->getDriver()->getAdapter()), Local::class); + $this->assertEquals(get_class($assetsDisk->getAdapter()), LocalFilesystemAdapter::class); } /** @@ -85,9 +87,10 @@ class FilesystemTest extends TestCase { $this->config('disk_driver.flarum-assets', 'null'); + /** @var FilesystemAdapter $assetsDisk */ $assetsDisk = $this->app()->getContainer()->make('filesystem')->disk('flarum-assets'); - $this->assertEquals(get_class($assetsDisk->getDriver()->getAdapter()), Local::class); + $this->assertEquals(get_class($assetsDisk->getAdapter()), LocalFilesystemAdapter::class); } /** @@ -101,9 +104,10 @@ class FilesystemTest extends TestCase $this->app()->getContainer()->make(SettingsRepositoryInterface::class)->set('disk_driver.flarum-assets', 'null'); + /** @var FilesystemAdapter $assetsDisk */ $assetsDisk = $this->app()->getContainer()->make('filesystem')->disk('flarum-assets'); - $this->assertEquals(get_class($assetsDisk->getDriver()->getAdapter()), NullAdapter::class); + $this->assertEquals(get_class($assetsDisk->getAdapter()), InMemoryFilesystemAdapter::class); } /** @@ -117,9 +121,10 @@ class FilesystemTest extends TestCase $this->config('disk_driver.flarum-assets', 'null'); + /** @var FilesystemAdapter $assetsDisk */ $assetsDisk = $this->app()->getContainer()->make('filesystem')->disk('flarum-assets'); - $this->assertEquals(get_class($assetsDisk->getDriver()->getAdapter()), NullAdapter::class); + $this->assertEquals(get_class($assetsDisk->getAdapter()), InMemoryFilesystemAdapter::class); } } @@ -127,7 +132,13 @@ class NullFilesystemDriver implements DriverInterface { public function build(string $diskName, SettingsRepositoryInterface $settings, Config $config, array $localConfig): Cloud { - return new FilesystemAdapter(new LeagueFilesystem(new NullAdapter())); + // The internal adapter + $adapter = new InMemoryFilesystemAdapter(); + + // The FilesystemOperator + $filesystem = new \League\Flysystem\Filesystem($adapter); + + return new FilesystemAdapter($filesystem, $adapter); } } diff --git a/framework/core/tests/integration/extenders/MailTest.php b/framework/core/tests/integration/extenders/MailTest.php index bea3c083a..9e1d7d2a7 100644 --- a/framework/core/tests/integration/extenders/MailTest.php +++ b/framework/core/tests/integration/extenders/MailTest.php @@ -16,8 +16,8 @@ use Flarum\Testing\integration\RetrievesAuthorizedUsers; use Flarum\Testing\integration\TestCase; use Illuminate\Contracts\Validation\Factory; use Illuminate\Support\MessageBag; -use Swift_NullTransport; -use Swift_Transport; +use Symfony\Component\Mailer\Transport\NullTransport; +use Symfony\Component\Mailer\Transport\TransportInterface; class MailTest extends TestCase { @@ -110,8 +110,8 @@ class CustomDriver implements DriverInterface return false; } - public function buildTransport(SettingsRepositoryInterface $settings): Swift_Transport + public function buildTransport(SettingsRepositoryInterface $settings): TransportInterface { - return new Swift_NullTransport; + return new NullTransport(); } } diff --git a/php-packages/testing/src/integration/Extension/ExtensionManagerIncludeCurrent.php b/php-packages/testing/src/integration/Extension/ExtensionManagerIncludeCurrent.php index afaeaa479..23c2787f3 100644 --- a/php-packages/testing/src/integration/Extension/ExtensionManagerIncludeCurrent.php +++ b/php-packages/testing/src/integration/Extension/ExtensionManagerIncludeCurrent.php @@ -21,8 +21,7 @@ use Illuminate\Filesystem\Filesystem; use Illuminate\Filesystem\FilesystemAdapter; use Illuminate\Support\Arr; use Illuminate\Support\Collection; -use League\Flysystem\Adapter\Local; -use League\Flysystem\Filesystem as FlysystemFilesystem; +use League\Flysystem\Local\LocalFilesystemAdapter; class ExtensionManagerIncludeCurrent extends ExtensionManager { @@ -108,6 +107,8 @@ class ExtensionManagerIncludeCurrent extends ExtensionManager */ protected function getAssetsFilesystem(): Cloud { - return new FilesystemAdapter(new FlysystemFilesystem(new Local($this->paths->public.'/assets'), ['url' => resolve('flarum.config')->url().'/assets'])); + $adapter = new LocalFilesystemAdapter($this->paths->public.'/assets'); + + return new FilesystemAdapter(new \League\Flysystem\Filesystem($adapter), $adapter); } }