diff --git a/.env-example b/.env-example new file mode 100644 index 0000000..8a64187 --- /dev/null +++ b/.env-example @@ -0,0 +1,2 @@ +COMPOSER_HOME=~/.config/composer +UID=1000 \ No newline at end of file diff --git a/.gitignore b/.gitignore index 31a345f..c9b4bcd 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,4 @@ tests/_support tests/_output tests/cases/yii2-app-advanced/_data/db.sqlite +.env diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..bf3b009 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,11 @@ +ARG PHP_VERSION="8.3-alpine" + +FROM php:$PHP_VERSION + +ADD https://github.com/mlocati/docker-php-extension-installer/releases/latest/download/install-php-extensions /usr/local/bin/ + +RUN chmod +x /usr/local/bin/install-php-extensions \ + && apk add --no-cache git \ + && install-php-extensions gd intl zip intl pcov @composer + +WORKDIR /var/www/html \ No newline at end of file diff --git a/composer.json b/composer.json index a447850..640301c 100644 --- a/composer.json +++ b/composer.json @@ -29,7 +29,8 @@ "codemix/yii2-localeurls": "^1.7", "codeception/module-asserts": ">= 3.0", "codeception/module-filesystem": "> 3.0", - "phpstan/phpstan": "^1.10" + "phpstan/phpstan": "^1.10", + "yiisoft/yii2-swiftmailer": "^2.0.0" }, "autoload":{ "classmap": ["src/"] diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..4350f7f --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,41 @@ +services: + + php80: &phpbase + user: ${UID} + volumes: + - ${COMPOSER_HOME}:/.config/composer:delegated + # Mount source-code for development + - ./:/var/www/html + env_file: + - .env + environment: + - XDEBUG_CONFIG=client_host=host.docker.internal + extra_hosts: + - "host.docker.internal:host-gateway" + build: + context: ./ + dockerfile: Dockerfile + args: + - PHP_VERSION=8.0-alpine + + php81: + <<: *phpbase + build: + args: + - PHP_VERSION=8.1-alpine + php82: + <<: *phpbase + build: + args: + - PHP_VERSION=8.2-alpine + + php83: + <<: *phpbase + build: + args: + - PHP_VERSION=8.3-alpine + php84: + <<: *phpbase + build: + args: + - PHP_VERSION=8.4-alpine diff --git a/src/Codeception/Lib/Connector/Yii2.php b/src/Codeception/Lib/Connector/Yii2.php index 1a76275..9a0dd15 100644 --- a/src/Codeception/Lib/Connector/Yii2.php +++ b/src/Codeception/Lib/Connector/Yii2.php @@ -14,6 +14,7 @@ use yii\base\ExitException; use yii\base\Security; use yii\base\UserException; +use yii\helpers\ArrayHelper; use yii\mail\MessageInterface; use yii\web\Application; use yii\web\ErrorHandler; @@ -422,33 +423,30 @@ protected function encodeCookies( */ protected function mockMailer(array $config): array { - // options that make sense for mailer mock - $allowedOptions = [ - 'htmlLayout', - 'textLayout', - 'messageConfig', - 'messageClass', - 'useFileTransport', - 'fileTransportPath', - 'fileTransportCallback', - 'view', - 'viewPath', - ]; - $mailerConfig = [ 'class' => TestMailer::class, 'callback' => function (MessageInterface $message) { $this->emails[] = $message; - } + }, + 'mailer' => [ + 'class' => \yii\symfonymailer\Mailer::class + ] ]; if (isset($config['components']['mailer']) && is_array($config['components']['mailer'])) { - foreach ($config['components']['mailer'] as $name => $value) { - if (in_array($name, $allowedOptions, true)) { - $mailerConfig[$name] = $value; - } - } + $mailerConfig['mailer'] = ArrayHelper::merge($mailerConfig['mailer'], $config['components']['mailer']); } + + /** + * Set transports only if known mailers that have this field is used + */ + if ($mailerConfig['mailer']['class'] instanceof \yii\symfonymailer\Mailer) { + $mailerConfig['mailer']['transport'] = \Symfony\Component\Mailer\Transport\NullTransport::class; + } + if ($mailerConfig['mailer']['class'] instanceof \yii\swiftmailer\Mailer) { + $mailerConfig['mailer']['transport'] = \Swift_Transport_NullTransport::class; + } + $config['components']['mailer'] = $mailerConfig; return $config; diff --git a/src/Codeception/Lib/Connector/Yii2/TestMailer.php b/src/Codeception/Lib/Connector/Yii2/TestMailer.php index 16e254d..ba3dc1f 100644 --- a/src/Codeception/Lib/Connector/Yii2/TestMailer.php +++ b/src/Codeception/Lib/Connector/Yii2/TestMailer.php @@ -1,24 +1,106 @@ mailer = Instance::ensure($this->mailer, MailerInterface::class); + } + + /** + * @param string $name + * @param array $params + * @return mixed + */ + public function __call($name, $params) + { + try { + return parent::__call($name, $params); + } catch (UnknownMethodException $e) { + return call_user_func_array([$this->mailer, $name], $params); + } + } + + /** + * @param string $name + * @return mixed + */ + public function __get($name) + { + try { + return parent::__get($name); + } catch (UnknownPropertyException $e) { + return $this->mailer->{$name}; + } + } + + /** + * @param string $name + * @param mixed $value + */ + public function __set($name, $value) + { + try { + parent::__set($name, $value); + } catch (UnknownPropertyException $e) { + $this->mailer->{$name} = $value; + } + } + + /** + * @inheritdoc + */ + public function compose($view = null, array $params = []): MessageInterface + { + $message = $this->mailer->compose($view, $params); + + if ($message instanceof BaseObject && $message->canSetProperty('mailer')) { + /** @phpstan-ignore property.notFound */ + $message->mailer = $this; + } else { + $reflection = new ReflectionClass($message); + if ($reflection->hasProperty('mailer')) { + /** @phpstan-ignore property.notFound */ + $message->mailer = $this; + } + } + + return $message; + } + + protected function sendMessage($message): bool { call_user_func($this->callback, $message); return true; } - - protected function saveMessage($message) + + protected function saveMessage($message): bool { call_user_func($this->callback, $message); return true;