From 2f4bdafa19c52b045c2c926e744b1b80cf5679aa Mon Sep 17 00:00:00 2001 From: Joshua Parker Date: Sun, 8 Oct 2023 09:23:17 -0600 Subject: [PATCH 01/25] Updated .gitignore. --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index d62bd6a..4aec902 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,6 @@ .idea +.env +config Scheduler/Tests vendor .php-cs-fixer.cache From a974f5056f38d4f57fd21ff5a4aefe5c0e0db378 Mon Sep 17 00:00:00 2001 From: Joshua Parker Date: Sun, 8 Oct 2023 09:26:55 -0600 Subject: [PATCH 02/25] Added Application constant so that version is changed in only one place. --- Application.php | 2 +- Console/ConsoleApplication.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Application.php b/Application.php index a26b57c..0f9a01d 100644 --- a/Application.php +++ b/Application.php @@ -30,7 +30,7 @@ class Application extends Container { use InvokerAware; - public const APP_VERSION = '1.0.0'; + public const APP_VERSION = '1.0.2'; public const MIN_PHP_VERSION = '8.2'; diff --git a/Console/ConsoleApplication.php b/Console/ConsoleApplication.php index 5acbac9..864730e 100644 --- a/Console/ConsoleApplication.php +++ b/Console/ConsoleApplication.php @@ -21,7 +21,7 @@ class ConsoleApplication extends SymfonyApplication public function __construct(protected Application $codefy) { - parent::__construct(name: 'CodefyPHP', version: '1.0.0'); + parent::__construct(name: 'CodefyPHP', version: Application::APP_VERSION); } public function run(InputInterface $input = null, OutputInterface $output = null): int From 3aa53a2231c2d6bbbd023d461e417e0704296e3c Mon Sep 17 00:00:00 2001 From: Joshua Parker Date: Tue, 10 Oct 2023 13:40:31 -0600 Subject: [PATCH 03/25] Updated shared aliases. --- Application.php | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Application.php b/Application.php index 0f9a01d..8af30e8 100644 --- a/Application.php +++ b/Application.php @@ -627,6 +627,7 @@ protected function coreAliases(): array \Psr\Http\Message\ServerRequestInterface::class => \Qubus\Http\ServerRequest::class, \Psr\Http\Message\ServerRequestFactoryInterface::class => \Qubus\Http\ServerRequestFactory::class, \Psr\Http\Message\RequestInterface::class => \Qubus\Http\Request::class, + \Psr\Http\Server\RequestHandlerInterface::class => \Relay\Runner::class, \Psr\Http\Message\ResponseInterface::class => \Qubus\Http\Response::class, \Psr\Cache\CacheItemInterface::class => \Qubus\Cache\Psr6\Item::class, \Psr\Cache\CacheItemPoolInterface::class => \Qubus\Cache\Psr6\ItemPool::class, @@ -648,11 +649,15 @@ protected function coreAliases(): array \Qubus\Cache\Adapter\CacheAdapter::class => \Qubus\Cache\Adapter\FileSystemCacheAdapter::class, \Codefy\Framework\Scheduler\Mutex\Locker::class => \Codefy\Framework\Scheduler\Mutex\CacheLocker::class, + \Psr\SimpleCache\CacheInterface::class => \Qubus\Cache\Psr16\SimpleCache::class, + \Qubus\Http\Session\PhpSession::class => \Qubus\Http\Session\NativeSession::class, \DateTimeZone::class => \Qubus\Support\DateTime\QubusDateTimeZone::class, \Symfony\Component\Console\Input\InputInterface::class => \Symfony\Component\Console\Input\ArgvInput::class, \Symfony\Component\Console\Output\OutputInterface::class => \Symfony\Component\Console\Output\ConsoleOutput::class, + \Qubus\Http\Cookies\Factory\HttpCookieFactory::class => \Qubus\Http\Cookies\Factory\CookieFactory::class, + \Qubus\Http\Session\Storage\SessionStorage::class => \Qubus\Http\Session\Storage\SimpleCacheStorage::class, ] ]; } From 2fbdf53cd51311d7ceeb8ccd2d29bc5ed7d9dcda Mon Sep 17 00:00:00 2001 From: Joshua Parker Date: Thu, 12 Oct 2023 13:18:28 -0600 Subject: [PATCH 04/25] Added session. --- Application.php | 7 +++++-- Http/BaseController.php | 3 ++- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/Application.php b/Application.php index 8af30e8..c963ec3 100644 --- a/Application.php +++ b/Application.php @@ -656,8 +656,11 @@ protected function coreAliases(): array => \Symfony\Component\Console\Input\ArgvInput::class, \Symfony\Component\Console\Output\OutputInterface::class => \Symfony\Component\Console\Output\ConsoleOutput::class, - \Qubus\Http\Cookies\Factory\HttpCookieFactory::class => \Qubus\Http\Cookies\Factory\CookieFactory::class, - \Qubus\Http\Session\Storage\SessionStorage::class => \Qubus\Http\Session\Storage\SimpleCacheStorage::class, + \Qubus\Http\Cookies\Factory\HttpCookieFactory::class + => \Qubus\Http\Cookies\Factory\CookieFactory::class, + \Qubus\Http\Session\Storage\SessionStorage::class + => \Qubus\Http\Session\Storage\SimpleCacheStorage::class, + \Qubus\Http\Session\HttpSession::class => \Qubus\Http\Session\SessionData::class, ] ]; } diff --git a/Http/BaseController.php b/Http/BaseController.php index 78e00ee..2998fe4 100644 --- a/Http/BaseController.php +++ b/Http/BaseController.php @@ -7,6 +7,7 @@ use Codefy\Framework\Contracts\RoutingController; use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\ServerRequestInterface; +use Qubus\Http\Session\HttpSession; use Qubus\Routing\Controller\Controller; use Qubus\Routing\Router; use Qubus\View\Native\NativeLoader; @@ -22,7 +23,7 @@ public function __construct( protected ?ResponseInterface $response = null, protected ?Router $router = null, protected ?Renderer $view = null, - + protected ?HttpSession $httpSession = null, ) { $this->setRequest($request ?? app(name: ServerRequestInterface::class)); $this->response = $response ?? app(name: ResponseInterface::class); From 95e3d88aa88afa6fa64158c78caef51e2d08fd1b Mon Sep 17 00:00:00 2001 From: Joshua Parker Date: Thu, 12 Oct 2023 13:26:03 -0600 Subject: [PATCH 05/25] Added SapiEmitter to dispatchRouter method. --- Http/Kernel.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Http/Kernel.php b/Http/Kernel.php index 8b84a28..b60790e 100644 --- a/Http/Kernel.php +++ b/Http/Kernel.php @@ -7,6 +7,7 @@ use Codefy\Framework\Application; use Codefy\Framework\Contracts\Kernel as HttpKernel; use Exception; +use Laminas\HttpHandlerRunner\Emitter\SapiEmitter; use Qubus\Error\Handlers\DebugErrorHandler; use Qubus\Error\Handlers\ErrorHandler; use Qubus\Error\Handlers\ProductionErrorHandler; @@ -62,7 +63,7 @@ protected function dispatchRouter(): bool files: $_FILES ) ), - emitter: null + emitter: new SapiEmitter() ); } From 27df23203c35e2c6f75e652ef914be14220224d3 Mon Sep 17 00:00:00 2001 From: Joshua Parker Date: Thu, 12 Oct 2023 13:42:19 -0600 Subject: [PATCH 06/25] Updated version value. --- Application.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Application.php b/Application.php index c963ec3..f6488ff 100644 --- a/Application.php +++ b/Application.php @@ -30,7 +30,7 @@ class Application extends Container { use InvokerAware; - public const APP_VERSION = '1.0.2'; + public const APP_VERSION = '1.0.3'; public const MIN_PHP_VERSION = '8.2'; From 460a28d24aa65c0d01db844bdae37e4ae88e143a Mon Sep 17 00:00:00 2001 From: Joshua Parker Date: Tue, 17 Oct 2023 01:06:36 -0600 Subject: [PATCH 07/25] Updated constructor parameter. --- Http/BaseController.php | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/Http/BaseController.php b/Http/BaseController.php index 2998fe4..1fea0e9 100644 --- a/Http/BaseController.php +++ b/Http/BaseController.php @@ -7,7 +7,7 @@ use Codefy\Framework\Contracts\RoutingController; use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\ServerRequestInterface; -use Qubus\Http\Session\HttpSession; +use Qubus\Http\Session\SessionService; use Qubus\Routing\Controller\Controller; use Qubus\Routing\Router; use Qubus\View\Native\NativeLoader; @@ -23,12 +23,14 @@ public function __construct( protected ?ResponseInterface $response = null, protected ?Router $router = null, protected ?Renderer $view = null, - protected ?HttpSession $httpSession = null, + protected ?SessionService $sessionService = null, ) { - $this->setRequest($request ?? app(name: ServerRequestInterface::class)); + $this->setRequest(request: $request ?? app(name: ServerRequestInterface::class)); $this->response = $response ?? app(name: ResponseInterface::class); $this->router = $router ?? app(name: 'router'); - $this->setView($view ?? new NativeLoader(config('view.path'))); + $this->setView(view: $view ?? new NativeLoader(config(key: 'view.path'))); + $this->sessionService = $sessionService ?? app(name: SessionService::class); + } /** From 8551bab0ae4dfacf51de4a543de43064215ed000 Mon Sep 17 00:00:00 2001 From: Joshua Parker Date: Tue, 17 Oct 2023 01:24:56 -0600 Subject: [PATCH 08/25] Bumped up application version value. --- Application.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Application.php b/Application.php index f6488ff..3540746 100644 --- a/Application.php +++ b/Application.php @@ -30,7 +30,7 @@ class Application extends Container { use InvokerAware; - public const APP_VERSION = '1.0.3'; + public const APP_VERSION = '1.0.4'; public const MIN_PHP_VERSION = '8.2'; From 9f48d6b7374c1d1f2dc7c6b640eb661419b1bb96 Mon Sep 17 00:00:00 2001 From: Joshua Parker Date: Tue, 17 Oct 2023 08:22:16 -0600 Subject: [PATCH 09/25] Breaking change needed to fix caching bug. --- Http/BaseController.php | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/Http/BaseController.php b/Http/BaseController.php index 1fea0e9..4bcfe2b 100644 --- a/Http/BaseController.php +++ b/Http/BaseController.php @@ -13,24 +13,18 @@ use Qubus\View\Native\NativeLoader; use Qubus\View\Renderer; -use function Codefy\Framework\Helpers\app; use function Codefy\Framework\Helpers\config; class BaseController extends Controller implements RoutingController { public function __construct( - protected ?ServerRequestInterface $request = null, - protected ?ResponseInterface $response = null, - protected ?Router $router = null, + protected SessionService $sessionService, + protected ServerRequestInterface $request, + protected ResponseInterface $response, + protected Router $router, protected ?Renderer $view = null, - protected ?SessionService $sessionService = null, ) { - $this->setRequest(request: $request ?? app(name: ServerRequestInterface::class)); - $this->response = $response ?? app(name: ResponseInterface::class); - $this->router = $router ?? app(name: 'router'); $this->setView(view: $view ?? new NativeLoader(config(key: 'view.path'))); - $this->sessionService = $sessionService ?? app(name: SessionService::class); - } /** From 50f8439b06fd834ecfe4e252706601223e2901b3 Mon Sep 17 00:00:00 2001 From: Joshua Parker Date: Tue, 17 Oct 2023 08:22:35 -0600 Subject: [PATCH 10/25] Bumped version value. --- Application.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Application.php b/Application.php index 3540746..f77d484 100644 --- a/Application.php +++ b/Application.php @@ -30,7 +30,7 @@ class Application extends Container { use InvokerAware; - public const APP_VERSION = '1.0.4'; + public const APP_VERSION = '1.0.5'; public const MIN_PHP_VERSION = '8.2'; From 0a1c9c4e0ee052a608b2ce098ff042f74c0b49ff Mon Sep 17 00:00:00 2001 From: Joshua Parker Date: Wed, 25 Oct 2023 22:49:24 -0600 Subject: [PATCH 11/25] Updated base middlewares and named parameters. --- Application.php | 43 ++++++++++++++++++++++++++++--------------- 1 file changed, 28 insertions(+), 15 deletions(-) diff --git a/Application.php b/Application.php index f77d484..9544e97 100644 --- a/Application.php +++ b/Application.php @@ -6,6 +6,7 @@ use Codefy\Framework\Support\Paths; use Psr\Container\ContainerInterface; +use Qubus\Config\ConfigContainer; use Qubus\Dbal\Connection; use Qubus\Dbal\DB; use Qubus\Exception\Data\TypeException; @@ -74,7 +75,7 @@ public function __construct(array $params) self::$APP = $this; self::$ROOT_PATH = $this->basePath; - parent::__construct(InjectorFactory::create($this->coreAliases())); + parent::__construct(InjectorFactory::create(config: $this->coreAliases())); $this->registerDefaultServiceProviders(); } @@ -83,20 +84,21 @@ public function __construct(array $params) */ public function getDbConnection(): Connection { + /** @var $config ConfigContainer */ $config = $this->make(name: 'codefy.config'); $connection = env(key: 'DB_CONNECTION', default: 'default'); return DB::connection([ - 'driver' => $config->getConfigKey("database.connections.{$connection}.driver"), - 'host' => $config->getConfigKey("database.connections.{$connection}.host", 'localhost'), - 'port' => $config->getConfigKey("database.connections.{$connection}.port", 3306), - 'charset' => $config->getConfigKey("database.connections.{$connection}.charset", 'utf8mb4'), - 'collation' => $config->getConfigKey("database.connections.{$connection}.collation", 'utf8mb4_unicode_ci'), - 'username' => $config->getConfigKey("database.connections.{$connection}.username"), - 'password' => $config->getConfigKey("database.connections.{$connection}.password"), - 'dbname' => $config->getConfigKey("database.connections.{$connection}.dbname"), - 'prefix' => $config->getConfigKey("database.connections.{$connection}.prefix", ''), + 'driver' => $config->getConfigKey(key: "database.connections.{$connection}.driver"), + 'host' => $config->getConfigKey(key: "database.connections.{$connection}.host", default: 'localhost'), + 'port' => $config->getConfigKey(key: "database.connections.{$connection}.port", default: 3306), + 'charset' => $config->getConfigKey(key: "database.connections.{$connection}.charset", default: 'utf8mb4'), + 'collation' => $config->getConfigKey(key: "database.connections.{$connection}.collation", default: 'utf8mb4_unicode_ci'), + 'username' => $config->getConfigKey(key: "database.connections.{$connection}.username"), + 'password' => $config->getConfigKey(key: "database.connections.{$connection}.password"), + 'dbname' => $config->getConfigKey(key: "database.connections.{$connection}.dbname"), + 'prefix' => $config->getConfigKey(key: "database.connections.{$connection}.prefix", default: ''), ]); } @@ -106,13 +108,14 @@ public function getDbConnection(): Connection */ public function getDB(): ?OrmBuilder { + /** @var $config ConfigContainer */ $config = $this->make(name: 'codefy.config'); $connection = env(key: 'DB_CONNECTION', default: 'default'); return new OrmBuilder( connection: $this->getDbConnection(), - tablePrefix: $config->getConfigKey("database.connections.{$connection}.prefix", '') + tablePrefix: $config->getConfigKey(key: "database.connections.{$connection}.prefix", default: '') ); } @@ -231,15 +234,17 @@ public function forceRegisterServiceProvider(string|Serviceable|Bootable $provid * * @return void * @throws TypeException + * @throws Exception */ public function registerConfiguredServiceProviders(): void { + /** @var $config ConfigContainer */ $config = $this->make(name: 'codefy.config'); - $providers = $config->getConfigKey('app.providers'); + $providers = $config->getConfigKey(key: 'app.providers'); foreach ($providers as $serviceProvider) { - $this->registerServiceProvider($serviceProvider); + $this->registerServiceProvider(serviceProvider: $serviceProvider); } } @@ -592,9 +597,15 @@ public function withBaseMiddlewares(array $middlewares): void $this->baseMiddlewares = $middlewares; } + /** + * @throws Exception + */ public function getBaseMiddlewares(): array { - return array_merge([], $this->baseMiddlewares); + /** @var $config ConfigContainer */ + $config = $this->make(name: 'codefy.config'); + + return array_merge($config->getConfigKey(key: 'app.base_middlewares'), $this->baseMiddlewares); } public function isRunningInConsole(): bool @@ -606,12 +617,14 @@ public function isRunningInConsole(): bool * Determine if the application is running with debug mode enabled. * * @return bool + * @throws Exception */ public function hasDebugModeEnabled(): bool { + /** @var $config ConfigContainer */ $config = $this->make(name: 'codefy.config'); - if ($config->getConfigKey('app.debug') === 'true') { + if ($config->getConfigKey(key: 'app.debug') === 'true') { return true; } From 458606da34ceaf9ce8c3a9412ebebfb157116a40 Mon Sep 17 00:00:00 2001 From: Joshua Parker Date: Mon, 30 Oct 2023 15:17:14 -0600 Subject: [PATCH 12/25] Fixed visibility bug. --- Support/LocalStorage.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Support/LocalStorage.php b/Support/LocalStorage.php index d59cfe6..de7ac4e 100644 --- a/Support/LocalStorage.php +++ b/Support/LocalStorage.php @@ -53,12 +53,12 @@ private static function setVisibilityConverterByDiskName(string $name): array { return [ 'file' => [ - 'public' => self::getConfigForDriverName(name: $name)['visibility']['file']['public'], - 'private' => self::getConfigForDriverName(name: $name)['visibility']['file']['private'], + 'public' => self::getConfigForDriverName(name: $name)['permission']['file']['public'], + 'private' => self::getConfigForDriverName(name: $name)['permission']['file']['private'], ], 'dir' => [ - 'public' => self::getConfigForDriverName(name: $name)['visibility']['dir']['public'], - 'private' => self::getConfigForDriverName(name: $name)['visibility']['dir']['private'], + 'public' => self::getConfigForDriverName(name: $name)['permission']['dir']['public'], + 'private' => self::getConfigForDriverName(name: $name)['permission']['dir']['private'], ], ]; } From c292222d452700f1d104eefbd2d940f892c4d1fd Mon Sep 17 00:00:00 2001 From: Joshua Parker Date: Mon, 30 Oct 2023 20:34:35 -0600 Subject: [PATCH 13/25] Bumped version value. --- Application.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Application.php b/Application.php index 9544e97..3366324 100644 --- a/Application.php +++ b/Application.php @@ -31,7 +31,7 @@ class Application extends Container { use InvokerAware; - public const APP_VERSION = '1.0.5'; + public const APP_VERSION = '1.0.6'; public const MIN_PHP_VERSION = '8.2'; From 7fa647e69ecdd3eb93d95ac1380d938df022e600 Mon Sep 17 00:00:00 2001 From: Joshua Parker Date: Tue, 7 Nov 2023 01:51:05 -0700 Subject: [PATCH 14/25] Updated mailer library. --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 8e3d1a7..3231ff1 100644 --- a/composer.json +++ b/composer.json @@ -22,7 +22,7 @@ "qubus/expressive": "^1", "qubus/filesystem": "^3", "qubus/injector": "^3", - "qubus/mail": "^3", + "qubus/mail": "^4", "qubus/router": "^3", "qubus/security": "^3", "qubus/support": "^3", From 6c13a24fd4503d80ad7914eeb75e5374583a3b01 Mon Sep 17 00:00:00 2001 From: Joshua Parker Date: Tue, 7 Nov 2023 01:51:40 -0700 Subject: [PATCH 15/25] Ignore files directory. --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 4aec902..0269de0 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,7 @@ .idea .env config +files Scheduler/Tests vendor .php-cs-fixer.cache From 48354f461c747d9ea93e967b0fc14307edc7b24a Mon Sep 17 00:00:00 2001 From: Joshua Parker Date: Tue, 7 Nov 2023 01:52:05 -0700 Subject: [PATCH 16/25] Created mailer wrapper class and function. --- Helpers/core.php | 104 +++++++++++++++++++++++++++++++++++++++ Support/CodefyMailer.php | 13 +++++ 2 files changed, 117 insertions(+) create mode 100644 Support/CodefyMailer.php diff --git a/Helpers/core.php b/Helpers/core.php index 86bc013..184449b 100644 --- a/Helpers/core.php +++ b/Helpers/core.php @@ -5,12 +5,16 @@ namespace Codefy\Framework\Helpers; use Codefy\Framework\Application; +use Codefy\Framework\Factory\FileLoggerFactory; +use Codefy\Framework\Support\CodefyMailer; use Qubus\Config\Collection; use Qubus\Dbal\Connection; use Qubus\Exception\Exception; use Qubus\Expressive\OrmBuilder; +use ReflectionException; use function file_exists; +use function Qubus\Security\Helpers\__observer; use function Qubus\Support\Helpers\is_false__; use function Qubus\Support\Helpers\is_null__; use function rtrim; @@ -106,3 +110,103 @@ function dbal(): Connection { return Application::$APP->getDbConnection(); } + +/** + * Alternative to PHP's native mail function with SMTP support. + * + * This is a simple mail function to see for testing or for + * sending simple email messages. + * + * @param string|array $to Recipient(s) + * @param string $subject Subject of the email. + * @param string $message The email body. + * @param array $headers An array of headers. + * @param array $attachments An array of attachments. + * @return bool + * @throws Exception|ReflectionException|\PHPMailer\PHPMailer\Exception + */ +function mail(string|array $to, string $subject, string $message, array $headers = [], array $attachments = []): bool +{ + // Instantiate CodefyMailer. + $instance = new CodefyMailer(config: app(name: 'codefy.config')); + + // Set the mailer transport. + $instance = config(key: 'mailer.mail_transport') === 'smtp' ? $instance->withSmtp() : $instance->withIsMail(); + + // Detect HTML markdown. + if (substr_count(haystack: $message, needle: '= 1) { + $instance = $instance->withHtml(isHtml: true); + } + + // Build recipient(s). + $instance = $instance->withTo(address: $to); + + // Set from name and from email from environment variables. + __observer()->filter->addFilter('mail.from.name', fn() => env(key: 'MAILER_FROM_NAME')); + __observer()->filter->addFilter('mail.from.email', fn() => env(key: 'MAILER_FROM_EMAIL')); + // Set charset + __observer()->filter->addFilter('mail.charset', fn() => 'utf-8'); + + // Loop through the filters. + foreach (__observer()->filter->getHooks() as $hook) { + if ($hook['hook'] === 'mail.from.name') { + $fromName = $hook['callback'](); + } + + if ($hook['hook'] === 'mail.from.email') { + $fromEmail = $hook['callback'](); + } + + if ($hook['hook'] === 'mail.charset') { + $charset = $hook['callback'](); + } + } + + // Set email subject and body. + $instance = $instance->withSubject(subject: $subject)->withBody(data: $message); + + // Check for other headers and loop through them. + if (!empty($headers)) { + foreach ($headers as $name => $content) { + if ($name === 'cc') { + $instance = $instance->withCc(address: $content); + } + + if ($name === 'bcc') { + $instance = $instance->withBcc(address: $content); + } + + if ($name === 'replyTo') { + $instance = $instance->withReplyTo(address: $content); + } + + if (! in_array(needle: $name, haystack: ['MIME-Version','to','cc','bcc','replyTo'], strict: true)) { + $instance = $instance->withCustomHeader(name: $name, value: $content); + } + } + } + + // Set X-Mailer header + $instance = $instance->withXMailer(xmailer: 'CodefyPHP Framework ' . Application::APP_VERSION); + + // Set email charset + $instance = $instance->withCharset(charset: $charset ?? 'utf-8'); + + // Check if there are attachments and loop through them. + if (!empty($attachments)) { + foreach ($attachments as $filename => $filepath) { + $filename = is_string(value: $filename) ? $filename : ''; + $instance = $instance->withAttachment(path: $filepath, name: $filename); + } + } + + // Set sender. + $instance = $instance->withFrom(address: $fromEmail ?? '', name: $fromName ?? ''); + + try { + return $instance->send(); + } catch (\PHPMailer\PHPMailer\Exception $e) { + FileLoggerFactory::getLogger()->error($e->getMessage(), ['function' => '\Codefy\Framework\Helpers\mail']); + return false; + } +} diff --git a/Support/CodefyMailer.php b/Support/CodefyMailer.php new file mode 100644 index 0000000..b0b8ef5 --- /dev/null +++ b/Support/CodefyMailer.php @@ -0,0 +1,13 @@ + Date: Tue, 7 Nov 2023 01:52:38 -0700 Subject: [PATCH 17/25] Bumped version value. --- Application.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Application.php b/Application.php index 3366324..d1ebba8 100644 --- a/Application.php +++ b/Application.php @@ -31,7 +31,7 @@ class Application extends Container { use InvokerAware; - public const APP_VERSION = '1.0.6'; + public const APP_VERSION = '1.0.7'; public const MIN_PHP_VERSION = '8.2'; From 436dda20ff8a56ffcd3328014fdc33de04c9264e Mon Sep 17 00:00:00 2001 From: Joshua Parker Date: Tue, 7 Nov 2023 22:09:36 -0700 Subject: [PATCH 18/25] Replaced Swiftmailer with PHPMailer. --- Factory/FileLoggerSendmailFactory.php | 51 ------------------- Factory/FileLoggerSmtpFactory.php | 8 ++- ...tpFactory.php => PHPMailerSmtpFactory.php} | 9 ++-- Factory/SwiftMailerSendmailFactory.php | 22 -------- 4 files changed, 6 insertions(+), 84 deletions(-) delete mode 100644 Factory/FileLoggerSendmailFactory.php rename Factory/{SwiftMailerSmtpFactory.php => PHPMailerSmtpFactory.php} (52%) delete mode 100644 Factory/SwiftMailerSendmailFactory.php diff --git a/Factory/FileLoggerSendmailFactory.php b/Factory/FileLoggerSendmailFactory.php deleted file mode 100644 index b6ed717..0000000 --- a/Factory/FileLoggerSendmailFactory.php +++ /dev/null @@ -1,51 +0,0 @@ -attach( - object: new FileLogger(filesystem: $filesystem, threshold: LogLevel::INFO) - ); - - $mail = SwiftMailerSendmailFactory::create(); - - if (env(key: 'LOGGER_FROM_EMAIL') !== null && env(key: 'LOGGER_TO_EMAIL') !== null) { - $storage->attach(object: new SwiftMailerLogger(mailer: $mail, threshold: LogLevel::INFO, params: [ - 'from' => env(key: 'LOGGER_FROM_EMAIL'), - 'to' => env(key: 'LOGGER_TO_EMAIL'), - 'subject' => env(key: 'LOGGER_EMAIL_SUBJECT'), - ])); - } - - return new Logger(loggers: $storage); - } -} diff --git a/Factory/FileLoggerSmtpFactory.php b/Factory/FileLoggerSmtpFactory.php index ede4f92..1adb034 100644 --- a/Factory/FileLoggerSmtpFactory.php +++ b/Factory/FileLoggerSmtpFactory.php @@ -9,10 +9,9 @@ use Codefy\Framework\Support\LocalStorage; use Psr\Log\LoggerInterface; use Psr\Log\LogLevel; -use Qubus\Exception\Exception; use Qubus\Log\Logger; use Qubus\Log\Loggers\FileLogger; -use Qubus\Log\Loggers\SwiftMailerLogger; +use Qubus\Log\Loggers\PHPMailerLogger; use ReflectionException; use SplObjectStorage; @@ -24,7 +23,6 @@ class FileLoggerSmtpFactory implements LoggerFactory /** * @throws ReflectionException - * @throws Exception */ public static function getLogger(): LoggerInterface { @@ -36,10 +34,10 @@ public static function getLogger(): LoggerInterface object: new FileLogger(filesystem: $filesystem, threshold: LogLevel::INFO) ); - $mail = SwiftMailerSmtpFactory::create(); + $mail = PHPMailerSmtpFactory::create(); if (env(key: 'LOGGER_FROM_EMAIL') !== null && env(key: 'LOGGER_TO_EMAIL') !== null) { - $storage->attach(object: new SwiftMailerLogger(mailer: $mail, threshold: LogLevel::INFO, params: [ + $storage->attach(object: new PHPMailerLogger(mailer: $mail, threshold: LogLevel::INFO, params: [ 'from' => env(key: 'LOGGER_FROM_EMAIL'), 'to' => env(key: 'LOGGER_TO_EMAIL'), 'subject' => env(key: 'LOGGER_EMAIL_SUBJECT'), diff --git a/Factory/SwiftMailerSmtpFactory.php b/Factory/PHPMailerSmtpFactory.php similarity index 52% rename from Factory/SwiftMailerSmtpFactory.php rename to Factory/PHPMailerSmtpFactory.php index daff105..0d484c4 100644 --- a/Factory/SwiftMailerSmtpFactory.php +++ b/Factory/PHPMailerSmtpFactory.php @@ -5,18 +5,15 @@ namespace Codefy\Framework\Factory; use Codefy\Framework\Contracts\MailerFactory; -use Qubus\Exception\Exception; +use Codefy\Framework\Support\CodefyMailer; use Qubus\Mail\Mailer; use function Codefy\Framework\Helpers\app; -class SwiftMailerSmtpFactory implements MailerFactory +class PHPMailerSmtpFactory implements MailerFactory { - /** - * @throws Exception - */ public static function create(): Mailer { - return (new Mailer())->factory(driver: 'smtp', config: app(name: 'codefy.config')); + return new CodefyMailer(config: app(name: 'codefy.config')); } } diff --git a/Factory/SwiftMailerSendmailFactory.php b/Factory/SwiftMailerSendmailFactory.php deleted file mode 100644 index 4a76b37..0000000 --- a/Factory/SwiftMailerSendmailFactory.php +++ /dev/null @@ -1,22 +0,0 @@ -factory(driver: 'sendmail', config: app(name: 'codefy.config')); - } -} From 4119a261da56af808800dc80859d261b9f76984d Mon Sep 17 00:00:00 2001 From: Joshua Parker Date: Tue, 7 Nov 2023 22:45:31 -0700 Subject: [PATCH 19/25] Added mailer implementation to injector. --- Application.php | 1 + 1 file changed, 1 insertion(+) diff --git a/Application.php b/Application.php index d1ebba8..cdc044e 100644 --- a/Application.php +++ b/Application.php @@ -649,6 +649,7 @@ protected function coreAliases(): array \Qubus\Config\Path\Path::class => \Qubus\Config\Path\ConfigPath::class, \Qubus\Config\ConfigContainer::class => \Qubus\Config\Collection::class, \Qubus\EventDispatcher\EventDispatcher::class => \Qubus\EventDispatcher\Dispatcher::class, + \Qubus\Mail\Mailer::class => \Codefy\Framework\Support\CodefyMailer::class, 'mailer' => \Qubus\Mail\Mailer::class, 'dir.path' => Support\Paths::class, 'container' => self::class, From d1d2745ee1a55866738f66990060e94dc6476fe0 Mon Sep 17 00:00:00 2001 From: Joshua Parker Date: Thu, 9 Nov 2023 21:16:04 -0700 Subject: [PATCH 20/25] Added phpcs cache. --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 0269de0..ee42dc5 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,7 @@ config files Scheduler/Tests vendor +.phpcs-cache .php-cs-fixer.cache .phpunit.result.cache composer.lock From ef7f62b4eae924405d2105cd1b5df3e2718442a4 Mon Sep 17 00:00:00 2001 From: Joshua Parker Date: Thu, 9 Nov 2023 21:17:24 -0700 Subject: [PATCH 21/25] Imported php functions, fixed env function, and dynamic mailer transport. --- Helpers/core.php | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/Helpers/core.php b/Helpers/core.php index 184449b..51f65ab 100644 --- a/Helpers/core.php +++ b/Helpers/core.php @@ -14,10 +14,15 @@ use ReflectionException; use function file_exists; +use function in_array; +use function is_string; use function Qubus\Security\Helpers\__observer; use function Qubus\Support\Helpers\is_false__; use function Qubus\Support\Helpers\is_null__; use function rtrim; +use function sprintf; +use function substr_count; +use function ucfirst; /** * Get the available container instance. @@ -86,7 +91,7 @@ function get_fresh_bootstrap(): mixed */ function env(string $key, mixed $default = null): mixed { - return $_ENV[$key] ?? $default; + return $_ENV[$key] ?: $default; } /** @@ -131,7 +136,8 @@ function mail(string|array $to, string $subject, string $message, array $headers $instance = new CodefyMailer(config: app(name: 'codefy.config')); // Set the mailer transport. - $instance = config(key: 'mailer.mail_transport') === 'smtp' ? $instance->withSmtp() : $instance->withIsMail(); + $func = sprintf('with%s', ucfirst(config(key: 'mailer.mail_transport'))); + $instance = $instance->{$func}(); // Detect HTML markdown. if (substr_count(haystack: $message, needle: '= 1) { From 0ea15562d892bc0ddbc057f937eccd46e71a3138 Mon Sep 17 00:00:00 2001 From: Joshua Parker Date: Thu, 9 Nov 2023 21:29:55 -0700 Subject: [PATCH 22/25] Bumped up version value. --- Application.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Application.php b/Application.php index cdc044e..2512bb7 100644 --- a/Application.php +++ b/Application.php @@ -31,7 +31,7 @@ class Application extends Container { use InvokerAware; - public const APP_VERSION = '1.0.7'; + public const APP_VERSION = '1.0.8'; public const MIN_PHP_VERSION = '8.2'; From fe38a77b7cf1571afd50f3fc4af22e6e83198cc7 Mon Sep 17 00:00:00 2001 From: Joshua Parker Date: Fri, 10 Nov 2023 12:54:57 -0700 Subject: [PATCH 23/25] Fixed filters. --- Helpers/core.php | 25 +++++-------------------- 1 file changed, 5 insertions(+), 20 deletions(-) diff --git a/Helpers/core.php b/Helpers/core.php index 51f65ab..5f593c8 100644 --- a/Helpers/core.php +++ b/Helpers/core.php @@ -148,25 +148,10 @@ function mail(string|array $to, string $subject, string $message, array $headers $instance = $instance->withTo(address: $to); // Set from name and from email from environment variables. - __observer()->filter->addFilter('mail.from.name', fn() => env(key: 'MAILER_FROM_NAME')); - __observer()->filter->addFilter('mail.from.email', fn() => env(key: 'MAILER_FROM_EMAIL')); + $fromName = __observer()->filter->applyFilter('mail.from.name', env(key: 'MAILER_FROM_NAME')); + $fromEmail = __observer()->filter->applyFilter('mail.from.email', env(key: 'MAILER_FROM_EMAIL')); // Set charset - __observer()->filter->addFilter('mail.charset', fn() => 'utf-8'); - - // Loop through the filters. - foreach (__observer()->filter->getHooks() as $hook) { - if ($hook['hook'] === 'mail.from.name') { - $fromName = $hook['callback'](); - } - - if ($hook['hook'] === 'mail.from.email') { - $fromEmail = $hook['callback'](); - } - - if ($hook['hook'] === 'mail.charset') { - $charset = $hook['callback'](); - } - } + $charset = __observer()->filter->applyFilter('mail.charset', fn() => 'utf-8'); // Set email subject and body. $instance = $instance->withSubject(subject: $subject)->withBody(data: $message); @@ -196,7 +181,7 @@ function mail(string|array $to, string $subject, string $message, array $headers $instance = $instance->withXMailer(xmailer: 'CodefyPHP Framework ' . Application::APP_VERSION); // Set email charset - $instance = $instance->withCharset(charset: $charset ?? 'utf-8'); + $instance = $instance->withCharset(charset: $charset ?: 'utf-8'); // Check if there are attachments and loop through them. if (!empty($attachments)) { @@ -207,7 +192,7 @@ function mail(string|array $to, string $subject, string $message, array $headers } // Set sender. - $instance = $instance->withFrom(address: $fromEmail ?? '', name: $fromName ?? ''); + $instance = $instance->withFrom(address: $fromEmail, name: $fromName ?: ''); try { return $instance->send(); From 96ea1bbea121c49da97d59856c4190bb2e4ec132 Mon Sep 17 00:00:00 2001 From: Joshua Parker Date: Fri, 10 Nov 2023 16:16:23 -0700 Subject: [PATCH 24/25] Forgot to fix charset filter. --- Helpers/core.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Helpers/core.php b/Helpers/core.php index 5f593c8..a68b5fd 100644 --- a/Helpers/core.php +++ b/Helpers/core.php @@ -151,7 +151,7 @@ function mail(string|array $to, string $subject, string $message, array $headers $fromName = __observer()->filter->applyFilter('mail.from.name', env(key: 'MAILER_FROM_NAME')); $fromEmail = __observer()->filter->applyFilter('mail.from.email', env(key: 'MAILER_FROM_EMAIL')); // Set charset - $charset = __observer()->filter->applyFilter('mail.charset', fn() => 'utf-8'); + $charset = __observer()->filter->applyFilter('mail.charset', 'utf-8'); // Set email subject and body. $instance = $instance->withSubject(subject: $subject)->withBody(data: $message); From 0be549582d9729f1a265f199fd52dc2d116c998c Mon Sep 17 00:00:00 2001 From: Joshua Parker Date: Fri, 10 Nov 2023 16:20:16 -0700 Subject: [PATCH 25/25] Bumped up version value. --- Application.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Application.php b/Application.php index 2512bb7..02584b4 100644 --- a/Application.php +++ b/Application.php @@ -31,7 +31,7 @@ class Application extends Container { use InvokerAware; - public const APP_VERSION = '1.0.8'; + public const APP_VERSION = '1.0.9'; public const MIN_PHP_VERSION = '8.2';