├── config └── yii.php ├── src ├── Http │ ├── DummyResponse.php │ └── YiiApplicationMiddleware.php ├── Yii │ ├── Mail │ │ └── SwiftMailer.php │ ├── Log │ │ ├── Logger.php │ │ ├── Target.php │ │ └── Illuminated.php │ ├── Di │ │ └── Container.php │ ├── Db │ │ └── Connection.php │ ├── I18n │ │ └── I18n.php │ ├── Web │ │ ├── User.php │ │ ├── Response.php │ │ ├── Request.php │ │ └── Session.php │ └── Caching │ │ └── Cache.php ├── YiiIlluminateServiceProvider.php └── Console │ └── RenameNamespaceCommand.php ├── UPGRADE.md ├── database └── migrations │ └── initial_migration.php.stub.php ├── LICENSE.md ├── CHANGELOG.md ├── composer.json └── README.md /config/yii.php: -------------------------------------------------------------------------------- 1 | [ 15 | 'defaultEntryScript' => 'legacy/web/index.php', 16 | 'cleanup' => true, 17 | //'bootstrap' => 'config/bootstrap.php', 18 | /*'container' => [ 19 | '__class' => Yii2tech\Illuminate\Yii\Di\Container::class, 20 | ],*/ 21 | /*'logger' => [ 22 | '__class' => Yii2tech\Illuminate\Yii\Log\Logger::class, 23 | ],*/ 24 | ], 25 | ]; 26 | -------------------------------------------------------------------------------- /src/Http/DummyResponse.php: -------------------------------------------------------------------------------- 1 | 20 | * @since 1.0 21 | */ 22 | class DummyResponse extends Response 23 | { 24 | /** 25 | * {@inheritdoc} 26 | */ 27 | public function send(): static 28 | { 29 | return $this; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /UPGRADE.md: -------------------------------------------------------------------------------- 1 | Upgrading Instructions for Yii2 to Laravel Migration Package 2 | ============================================================ 3 | 4 | !!!IMPORTANT!!! 5 | 6 | The following upgrading instructions are cumulative. That is, 7 | if you want to upgrade from version A to version C and there is 8 | version B between A and C, you need to following the instructions 9 | for both A and B. 10 | 11 | Upgrade from 1.2.1 12 | ------------------ 13 | 14 | * Minimal required PHP version has been raised to 8.0. Make sure to update your environment accordingly. 15 | 16 | 17 | Upgrade from 1.1.2 18 | ------------------ 19 | 20 | * Virtual property `Yii2tech\Illuminate\Yii\Db\Connection::$laravelConnection` renamed to `Yii2tech\Illuminate\Yii\Db\Connection::$illuminateConnection`. 21 | Check references to this property and methods defining it in your code and fix them accordingly. 22 | 23 | * Method `Yii2tech\Illuminate\Yii\Web\User::convertLaravelIdentity()` renamed to `Yii2tech\Illuminate\Yii\Web\User::convertIlluminateIdentity()`. 24 | Check references to this method in your code and fix them accordingly. 25 | 26 | 27 | Upgrade from 1.0.0 28 | ------------------ 29 | 30 | * "illuminate/*" package requirements were raised to 6.0. Make sure to upgrade your code accordingly. 31 | -------------------------------------------------------------------------------- /src/Yii/Mail/SwiftMailer.php: -------------------------------------------------------------------------------- 1 | [ 20 | * 'mailer' => Yii2tech\Illuminate\Yii\Mail\SwiftMailer::class, 21 | * // ... 22 | * ], 23 | * // ... 24 | * ]; 25 | * ``` 26 | * 27 | * @see https://github.com/yiisoft/yii2-swiftmailer 28 | * @see \yii\swiftmailer\Mailer 29 | * @see \Illuminate\Mail\MailServiceProvider 30 | * 31 | * @author Paul Klimov 32 | * @since 1.0 33 | */ 34 | class SwiftMailer extends \yii\swiftmailer\Mailer 35 | { 36 | /** 37 | * {@inheritdoc} 38 | */ 39 | protected function createSwiftMailer() 40 | { 41 | return \Illuminate\Container\Container::getInstance()->make('swift.mailer'); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /database/migrations/initial_migration.php.stub.php: -------------------------------------------------------------------------------- 1 | -p -h 15 | * ``` 16 | * 17 | * Then copy content of the created dump file into '<<statement(<<run(); 26 | * ``` 27 | * 28 | * @author Paul Klimov 29 | * @since 1.0 30 | */ 31 | class Logger extends \yii\log\Logger 32 | { 33 | use Illuminated; 34 | 35 | /** 36 | * {@inheritdoc} 37 | */ 38 | public function init(): void 39 | { 40 | Component::init(); // skip parent init, avoiding `register_shutdown_function()` call. 41 | } 42 | 43 | /** 44 | * {@inheritdoc} 45 | */ 46 | public function log($message, $level, $category = 'application'): void 47 | { 48 | $level = $this->convertLogLevel($level); 49 | $context = [ 50 | 'category' => $category, 51 | ]; 52 | if (! is_string($message)) { 53 | // exceptions may not be serializable if in the call stack somewhere is a Closure 54 | if ($message instanceof \Throwable) { 55 | $context['exception'] = $message; 56 | $message = (string) $message; 57 | } else { 58 | $message = VarDumper::export($message); 59 | } 60 | } 61 | 62 | $this->getIlluminateLogger()->log($level, $message, $context); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/Yii/Log/Target.php: -------------------------------------------------------------------------------- 1 | [ 20 | * 'log' => [ 21 | * 'targets' => [ 22 | * [ 23 | * 'class' => Yii2tech\Illuminate\Yii\Log\Target::class, 24 | * ], 25 | * // ... 26 | * ], 27 | * ], 28 | * // ... 29 | * ], 30 | * // ... 31 | * ]; 32 | * ``` 33 | * 34 | * @author Paul Klimov 35 | * @since 1.0 36 | */ 37 | class Target extends \yii\log\Target 38 | { 39 | use Illuminated; 40 | 41 | /** 42 | * {@inheritdoc} 43 | */ 44 | public function export() 45 | { 46 | foreach ($this->messages as $message) { 47 | [$text, $level, $category, $timestamp] = $message; 48 | $context = [ 49 | 'time' => $timestamp, 50 | 'category' => $category, 51 | ]; 52 | 53 | if (! is_string($text)) { 54 | // exceptions may not be serializable if in the call stack somewhere is a Closure 55 | if ($text instanceof \Throwable) { 56 | $context['exception'] = $text; 57 | $text = (string) $text; 58 | } else { 59 | $text = VarDumper::export($text); 60 | } 61 | } 62 | 63 | $this->getIlluminateLogger()->log($this->convertLogLevel($level), $text, $context); 64 | } 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | Yii2 to Laravel Migration Package Change Log 2 | ============================================ 3 | 4 | 1.3.2, April 3, 2025 5 | -------------------- 6 | 7 | - Enh #15: Added support for "illuminate/*" 12.0 (klimov-paul) 8 | 9 | 10 | 1.3.1, March 25, 2024 11 | --------------------- 12 | 13 | - Enh: Added support for "illuminate/*" 11.0 (klimov-paul) 14 | 15 | 16 | 1.3.0, March 2, 2023 17 | -------------------- 18 | 19 | - Bug: Fixed compatibility with "symfony/http-foundation" 6.x for `DummyResponse::send()` (klimov-paul) 20 | - Bug #13: Fixed `Yii2tech\Illuminate\Yii\Log\Logger` and `Yii2tech\Illuminate\Yii\Caching\Cache` unable to pick up default related Illuminate object (klimov-paul) 21 | - Enh: Added support for "illuminate/support" 10.0 (klimov-paul) 22 | 23 | 24 | 1.2.1, February 9, 2022 25 | ----------------------- 26 | 27 | - Enh: Added support for "illuminate/*" 9.0 (klimov-paul) 28 | 29 | 30 | 1.2.0, September 9, 2020 31 | ------------------------ 32 | 33 | - Enh: Added support for "illuminate/*" 8.0 (klimov-paul) 34 | - Chg: Virtual property `Connection::$laravelConnection` renamed to `Connection::$illuminateConnection` (klimov-paul) 35 | - Chg: Method `User::convertLaravelIdentity()` renamed to `User::convertIlluminateIdentity()` (klimov-paul) 36 | 37 | 38 | 1.1.2, July 24, 2020 39 | -------------------- 40 | 41 | - Bug #8: Fixes environment determining (leandrogehlen) 42 | - Enh #7: `Yii2tech\Illuminate\Yii\Web\Request` now picks up URI info from illuminate one (klimov-paul) 43 | 44 | 45 | 1.1.1, March 4, 2020 46 | -------------------- 47 | 48 | - Bug #3: Fixed `Yii2tech\Illuminate\Yii\Di\Container` and `Yii2tech\Illuminate\Yii\Caching\Cache` unable to pick up default related Illuminate object (klimov-paul) 49 | - Enh: Added support for "illuminate/*" 7.0 (klimov-paul) 50 | 51 | 52 | 1.1.0, September 6, 2019 53 | ------------------------ 54 | 55 | - Enh: Added support for "illuminate/*" 6.0 (klimov-paul) 56 | 57 | 58 | 1.0.0, March 11, 2019 59 | --------------------- 60 | 61 | - Initial release. 62 | -------------------------------------------------------------------------------- /src/YiiIlluminateServiceProvider.php: -------------------------------------------------------------------------------- 1 | 17 | * @since 1.0 18 | */ 19 | class YiiIlluminateServiceProvider extends ServiceProvider 20 | { 21 | /** 22 | * Register any application services. 23 | */ 24 | public function register(): void 25 | { 26 | $this->registerPublications(); 27 | } 28 | 29 | /** 30 | * Bootstrap the application services. 31 | */ 32 | public function boot(): void 33 | { 34 | if ($this->app->runningInConsole()) { 35 | $this->bootCommands(); 36 | } 37 | } 38 | 39 | /** 40 | * Register resources to be published by the publish command. 41 | */ 42 | protected function registerPublications(): void 43 | { 44 | if (! $this->app->runningInConsole()) { 45 | return; 46 | } 47 | 48 | $this->publishes([ 49 | __DIR__ . '/../config/yii.php' => $this->app->make('path.config').DIRECTORY_SEPARATOR.'yii.php', 50 | ], 'config'); 51 | 52 | if (! class_exists(\InitialMigration::class)) { 53 | $timestamp = date('Y_m_d_His', time()); 54 | 55 | $this->publishes([ 56 | __DIR__.'/../database/migrations/initial_migration.php.stub.php' => $this->app->databasePath().'/migrations/'.$timestamp.'_initial_migration.php', 57 | ], 'migrations'); 58 | } 59 | } 60 | 61 | /** 62 | * Boots provided console commands. 63 | */ 64 | protected function bootCommands(): void 65 | { 66 | $this->commands([ 67 | RenameNamespaceCommand::class, 68 | ]); 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "yii2tech/illuminate", 3 | "description": "Yii2 to Laravel Migration Package", 4 | "keywords": ["yii2", "laravel", "illuminate", "migration", "switch"], 5 | "license": "BSD-3-Clause", 6 | "support": { 7 | "issues": "https://github.com/yii2tech/illuminate/issues", 8 | "wiki": "https://github.com/yii2tech/illuminate/wiki", 9 | "source": "https://github.com/yii2tech/illuminate" 10 | }, 11 | "authors": [ 12 | { 13 | "name": "Paul Klimov", 14 | "email": "klimov.paul@gmail.com" 15 | } 16 | ], 17 | "require": { 18 | "php": ">= 8.0", 19 | "yiisoft/yii2": "~2.0.14", 20 | "illuminate/console": "^6.0 || ^7.0 || ^8.0 || ^9.0 || ^10.0 || ^11.0 || ^12.0", 21 | "illuminate/http": "^6.0 || ^7.0 || ^8.0 || ^9.0 || ^10.0 || ^11.0 || ^12.0", 22 | "illuminatech/array-factory": "^1.2.6" 23 | }, 24 | "require-dev": { 25 | "illuminate/auth": "*", 26 | "illuminate/cache": "*", 27 | "illuminate/config": "*", 28 | "illuminate/database": "*", 29 | "illuminate/events": "*", 30 | "illuminate/hashing": "*", 31 | "illuminate/log": "*", 32 | "illuminate/translation": "*", 33 | "phpunit/phpunit": "^7.5 || ^8.0 || ^9.3 || ^10.5" 34 | }, 35 | "repositories": [ 36 | { 37 | "type": "composer", 38 | "url": "https://asset-packagist.org" 39 | } 40 | ], 41 | "autoload": { 42 | "psr-4": { 43 | "Yii2tech\\Illuminate\\": "src" 44 | } 45 | }, 46 | "autoload-dev": { 47 | "psr-4": { 48 | "Yii2tech\\Illuminate\\Test\\": "tests" 49 | } 50 | }, 51 | "extra": { 52 | "branch-alias": { 53 | "dev-master": "1.0.x-dev" 54 | }, 55 | "laravel": { 56 | "providers": [ 57 | "Yii2tech\\Illuminate\\YiiIlluminateServiceProvider" 58 | ] 59 | } 60 | }, 61 | "config": { 62 | "allow-plugins": { 63 | "yiisoft/yii2-composer": true 64 | } 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/Yii/Log/Illuminated.php: -------------------------------------------------------------------------------- 1 | 24 | * @since 1.0 25 | */ 26 | trait Illuminated 27 | { 28 | /** 29 | * @var \Illuminate\Log\Logger laravel logger instance. 30 | */ 31 | private $_illuminateLogger; 32 | 33 | /** 34 | * @return \Psr\Log\LoggerInterface 35 | */ 36 | public function getIlluminateLogger(): LoggerInterface 37 | { 38 | if ($this->_illuminateLogger === null) { 39 | $this->_illuminateLogger = $this->defaultIlluminateLogger(); 40 | } 41 | 42 | return $this->_illuminateLogger; 43 | } 44 | 45 | /** 46 | * @param \Psr\Log\LoggerInterface $laravelLogger 47 | * @return static self reference. 48 | */ 49 | public function setIlluminateLogger(LoggerInterface $laravelLogger): self 50 | { 51 | $this->_illuminateLogger = $laravelLogger; 52 | 53 | return $this; 54 | } 55 | 56 | /** 57 | * Returns default value for {@see $illuminateLogger} 58 | * 59 | * @return \Psr\Log\LoggerInterface logger instance. 60 | */ 61 | protected function defaultIlluminateLogger(): LoggerInterface 62 | { 63 | return \Illuminate\Support\Facades\Log::getFacadeRoot(); 64 | } 65 | 66 | /** 67 | * Converts Yii log level into PSR one. 68 | * 69 | * @param int $level Yii log level. 70 | * @return string PSR log level. 71 | */ 72 | protected function convertLogLevel($level): string 73 | { 74 | $matches = [ 75 | Logger::LEVEL_ERROR => LogLevel::ERROR, 76 | Logger::LEVEL_WARNING => LogLevel::WARNING, 77 | Logger::LEVEL_INFO => LogLevel::INFO, 78 | Logger::LEVEL_TRACE => LogLevel::DEBUG, 79 | Logger::LEVEL_PROFILE => LogLevel::DEBUG, 80 | Logger::LEVEL_PROFILE_BEGIN => LogLevel::DEBUG, 81 | Logger::LEVEL_PROFILE_END => LogLevel::DEBUG, 82 | ]; 83 | 84 | if (isset($matches[$level])) { 85 | return $matches[$level]; 86 | } 87 | 88 | return LogLevel::INFO; 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /src/Yii/Di/Container.php: -------------------------------------------------------------------------------- 1 | run(); 27 | * ``` 28 | * 29 | * @see \Illuminate\Contracts\Container\Container 30 | * 31 | * @property \Illuminate\Contracts\Container\Container $illuminateContainer related Laravel DI container. 32 | * 33 | * @author Paul Klimov 34 | * @since 1.0 35 | */ 36 | class Container extends \yii\di\Container 37 | { 38 | /** 39 | * @var \Illuminate\Contracts\Container\Container related Laravel DI container. 40 | */ 41 | private $_illuminateContainer; 42 | 43 | /** 44 | * @return \Illuminate\Contracts\Container\Container 45 | */ 46 | public function getIlluminateContainer(): ContainerContract 47 | { 48 | if ($this->_illuminateContainer === null) { 49 | $this->_illuminateContainer = $this->defaultIlluminateContainer(); 50 | } 51 | 52 | return $this->_illuminateContainer; 53 | } 54 | 55 | /** 56 | * @param \Illuminate\Contracts\Container\Container $illuminateContainer 57 | * @return static self reference. 58 | */ 59 | public function setIlluminateContainer(ContainerContract $illuminateContainer): self 60 | { 61 | $this->_illuminateContainer = $illuminateContainer; 62 | 63 | return $this; 64 | } 65 | 66 | /** 67 | * @return \Illuminate\Contracts\Container\Container default Laravel DI container. 68 | */ 69 | protected function defaultIlluminateContainer(): ContainerContract 70 | { 71 | return \Illuminate\Container\Container::getInstance(); 72 | } 73 | 74 | /** 75 | * {@inheritdoc} 76 | */ 77 | public function get($class, $params = [], $config = []) 78 | { 79 | if ($this->getIlluminateContainer()->has($class)) { 80 | return $this->getIlluminateContainer()->get($class); 81 | } 82 | 83 | return parent::get($class, $params, $config); 84 | } 85 | 86 | /** 87 | * {@inheritdoc} 88 | */ 89 | public function has($class): bool 90 | { 91 | if ($this->getIlluminateContainer()->has($class)) { 92 | return true; 93 | } 94 | 95 | return parent::has($class); 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /src/Yii/Db/Connection.php: -------------------------------------------------------------------------------- 1 | [ 26 | * 'db' => Yii2tech\Illuminate\Yii\Db\Connection::class, 27 | * // ... 28 | * ], 29 | * // ... 30 | * ]; 31 | * ``` 32 | * 33 | * @see \Illuminate\Database\Connection 34 | * 35 | * @property \Illuminate\Database\Connection $illuminateConnection related Laravel DB connection. 36 | * 37 | * @author Paul Klimov 38 | * @since 1.0 39 | */ 40 | class Connection extends \yii\db\Connection 41 | { 42 | /** 43 | * @var \Illuminate\Database\Connection Laravel DB connection instance. 44 | */ 45 | private $_illuminateConnection; 46 | 47 | /** 48 | * {@inheritdoc} 49 | */ 50 | public function open(): void 51 | { 52 | if ($this->pdo !== null) { 53 | return; 54 | } 55 | 56 | $this->pdo = $this->getIlluminateConnection()->getPdo(); 57 | } 58 | 59 | /** 60 | * {@inheritdoc} 61 | */ 62 | public function close(): void 63 | { 64 | if ($this->pdo === null) { 65 | return; 66 | } 67 | 68 | $this->getIlluminateConnection()->disconnect(); 69 | 70 | $this->pdo = null; 71 | } 72 | 73 | /** 74 | * @param LaravelConnection $connection Laravel DB connection to be used. 75 | * @return static self reference. 76 | */ 77 | public function setIlluminateConnection(LaravelConnection $connection): self 78 | { 79 | $this->_illuminateConnection = $connection; 80 | 81 | return $this; 82 | } 83 | 84 | /** 85 | * Returns Laravel DB connection instance. 86 | * 87 | * @return \Illuminate\Database\Connection connection instance. 88 | */ 89 | public function getIlluminateConnection(): LaravelConnection 90 | { 91 | if ($this->_illuminateConnection === null) { 92 | $this->_illuminateConnection = $this->defaultIlluminateConnection(); 93 | } 94 | 95 | return $this->_illuminateConnection; 96 | } 97 | 98 | /** 99 | * Defines default Laravel connection. 100 | * 101 | * @return LaravelConnection Laravel connection instance. 102 | */ 103 | protected function defaultIlluminateConnection(): LaravelConnection 104 | { 105 | return DB::connection(); 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 | 3 | 4 | 5 |

Yii2 to Laravel Migration Package

6 |
7 |

8 | 9 | This extension allows running Yii2 and Laravel applications simultaneously at the same project, 10 | facilitating graceful migration from Yii2 to Laravel. 11 | 12 | For license information check the [LICENSE](LICENSE.md)-file. 13 | 14 | [![Latest Stable Version](https://poser.pugx.org/yii2tech/illuminate/v/stable.png)](https://packagist.org/packages/yii2tech/illuminate) 15 | [![Total Downloads](https://poser.pugx.org/yii2tech/illuminate/downloads.png)](https://packagist.org/packages/yii2tech/illuminate) 16 | [![Build Status](https://github.com/yii2tech/illuminate/workflows/build/badge.svg)](https://github.com/yii2tech/illuminate/actions) 17 | 18 | 19 | Installation 20 | ------------ 21 | 22 | The preferred way to install this extension is through [composer](http://getcomposer.org/download/). 23 | 24 | Either run 25 | 26 | ``` 27 | php composer.phar require --prefer-dist yii2tech/illuminate 28 | ``` 29 | 30 | or add 31 | 32 | ```json 33 | "yii2tech/illuminate": "*" 34 | ``` 35 | 36 | to the require section of your composer.json. 37 | 38 | 39 | Why switch from Yii2 to Laravel? 40 | -------------------------------- 41 | 42 | It is sad to admit, but Yii is outdated technology, which does not keep up with the modern trends. 43 | The core team stick to the BC-keep policy too much since 2.0 release, which make Yii2 lacking of many modern approaches 44 | and features. 45 | While it is common requirement of the modern web project to provide "single page application" based on modern 46 | JS frameworks like ReactJS, EmberJS, VueJS and so on, Yii keeps enforcing JQuery, facilitating its usage and requiring 47 | its installation. 48 | The BC breaking changes, which are supposed to change the situation, like accepting PSR standards for caching and logging, 49 | separating JQuery from the Yii core and so on, are frozen till the future 3.0 release, which can not be expected in any 50 | near future. 51 | 52 | Even when Yii 3.0 will be released, it will hold many BC breaking changes and totally different architecture concept, 53 | regarding of DI and Service Locator usage. This will make migration from Yii 2.x to Yii 3.0 to be the matter of entire 54 | project rewrite, as it already was for migration from Yii 1.x to Yii 2.0. If this is inevitable fate of your project, 55 | why not start code migration now, choosing more reliable technology as its target? 56 | Laravel is most popular PHP framework with solid commercial background and large community. Choosing it will likely bring 57 | good foundation for your project in the long term. 58 | 59 | **Heads up!** Whether to switch from one technology to another or not - is **your own** choice. You take the responsibility 60 | for this decision, and you will have to deal with it consequences. Do not blame anyone else for the troubles and obstacles 61 | you will have to face on the chosen path. 62 | 63 | 64 | Usage 65 | ----- 66 | 67 | Migration of existing project from one PHP framework to another can not be done by single day. Most likely you have spent 68 | several months or even years creating your current codebase, and its update will also take much time. 69 | 70 | This extension allows running Yii2 and Laravel applications simultaneously at the same project, allowing resolving of 71 | incoming HTTP requests by one of these applications depending on, which one has a matching route defined for it. 72 | This means all URL routes defined in Yii application will continue to function, while new ones may be resolved by 73 | Laravel. This facilitates graceful migration from one framework to another, allowing progressive transfer of the 74 | URL routes handling (e.g. controllers) from Yii2 to Laravel. 75 | 76 | **Heads up!** This package provides tools and libraries helping project migration, however, do not expect it somehow 77 | magically do all the job for you. The package helps solving basic problems and supports the quick start for the process, 78 | but most of the toil will lay on your shoulders. Be ready for it. 79 | 80 | 81 | Documentation 82 | ------------- 83 | 84 | Documentation is at [docs/README.md](docs/README.md). 85 | -------------------------------------------------------------------------------- /src/Console/RenameNamespaceCommand.php: -------------------------------------------------------------------------------- 1 | 18 | * @since 1.0 19 | */ 20 | class RenameNamespaceCommand extends Command 21 | { 22 | use ConfirmableTrait; 23 | 24 | /** 25 | * {@inheritdoc} 26 | */ 27 | protected $name = 'namespace:rename'; 28 | 29 | /** 30 | * {@inheritdoc} 31 | */ 32 | protected $signature = 'namespace:rename {path} 33 | {--from=app : Namespace to be renamed} 34 | {--to=legacy : New namespace name} 35 | {--force : Force the operation to run when in production}'; 36 | 37 | /** 38 | * {@inheritdoc} 39 | */ 40 | protected $description = 'Renames root namespace around PHP files in the specified directory.'; 41 | 42 | /** 43 | * Execute the console command. 44 | * 45 | * @return mixed 46 | */ 47 | public function handle() 48 | { 49 | $path = $this->argument('path'); 50 | 51 | $namespaceFrom = trim($this->option('from'), '\\'); 52 | $namespaceTo = trim($this->option('to'), '\\'); 53 | 54 | if (! $this->confirmToProceed("Namespace '{$namespaceFrom}' will be changed to '{$namespaceTo}' will be replaced at '{$path}' files.")) { 55 | return; 56 | } 57 | 58 | $totalCount = 0; 59 | $modifiedCount = 0; 60 | 61 | foreach ($this->findFiles($path) as $file) { 62 | $totalCount++; 63 | 64 | if ($this->renameNamespace($file, $namespaceFrom, $namespaceTo)) { 65 | $this->line('Modified: '.$file->getPathname()); 66 | $modifiedCount++; 67 | } 68 | } 69 | 70 | $this->info("Processed: {$totalCount} files. Modified: {$modifiedCount} files."); 71 | } 72 | 73 | /** 74 | * Finds the files for the replacement. 75 | * 76 | * @param string $path path to directory to be searched. 77 | * @return \Iterator|\Symfony\Component\Finder\SplFileInfo[] found files. 78 | */ 79 | protected function findFiles($path): iterable 80 | { 81 | return Finder::create() 82 | ->files() 83 | ->ignoreDotFiles(true) 84 | ->ignoreVCS(true) 85 | ->name('*.php') 86 | ->in($path) 87 | ->getIterator(); 88 | } 89 | 90 | /** 91 | * Renames namespace usages in given PHP file. 92 | * 93 | * @param string $file file name. 94 | * @param string $namespaceFrom namespace to be renamed 95 | * @param string $namespaceTo new namespace name. 96 | * @return bool whether file has been updated or not. 97 | */ 98 | protected function renameNamespace(string $file, string $namespaceFrom, string $namespaceTo): bool 99 | { 100 | $content = file_get_contents($file); 101 | 102 | $newContent = preg_replace_callback('/^(namespace\\s+)(\\\\?'.preg_quote($namespaceFrom).')([^\\s]*;)(\\s*)$/m', function ($matches) use ($namespaceTo) { 103 | return $matches[1].$namespaceTo.$matches[3].$matches[4]; 104 | }, $content); 105 | 106 | $newContent = preg_replace_callback('/^(use\\s+)(\\\\?'.preg_quote($namespaceFrom).')([^\\s]*;)(\\s*)$/m', function ($matches) use ($namespaceTo) { 107 | return $matches[1].$namespaceTo.$matches[3].$matches[4]; 108 | }, $newContent); 109 | 110 | $newContent = preg_replace_callback('/(\\\\?)('.preg_quote($namespaceFrom).')(\\\\[^\\s]+::class)/m', function ($matches) use ($namespaceTo) { 111 | return $matches[1].$namespaceTo.$matches[3]; 112 | }, $newContent); 113 | 114 | $newContent = preg_replace_callback('/(@see \\\\?)('.preg_quote($namespaceFrom).')(\\\\[^\\s]+\\s+)/m', function ($matches) use ($namespaceTo) { 115 | return $matches[1].$namespaceTo.$matches[3]; 116 | }, $newContent); 117 | 118 | if (sha1($content) !== sha1($newContent)) { 119 | file_put_contents($file, $newContent); 120 | 121 | return true; 122 | } 123 | 124 | return false; 125 | } 126 | } 127 | -------------------------------------------------------------------------------- /src/Yii/I18n/I18n.php: -------------------------------------------------------------------------------- 1 | [ 27 | * 'i18n' => [ 28 | * 'class' => Yii2tech\Illuminate\Yii\I18n\I18n::class, 29 | * 'illuminateCategories' => [ 30 | * 'auth', 31 | * 'validation', 32 | * ], 33 | * ], 34 | * // ... 35 | * ], 36 | * // ... 37 | * ]; 38 | * ``` 39 | * 40 | * @see \Illuminate\Translation\Translator 41 | * 42 | * @property \Illuminate\Translation\Translator $illuminateTranslator related Laravel translator. 43 | * 44 | * @author Paul Klimov 45 | * @since 1.0 46 | */ 47 | class I18n extends \yii\i18n\I18N 48 | { 49 | /** 50 | * @var string[] list of translation categories, which should be passed to {@see $illuminateTranslator}. 51 | * Messages from these categories will be translated directly via Laravel translator without involving Yii. 52 | * Translation message key will be composed by concatenation of category, dot symbol ('.') and message. 53 | */ 54 | public $illuminateCategories = []; 55 | 56 | /** 57 | * @var \Illuminate\Translation\Translator related Laravel translator. 58 | */ 59 | private $_illuminateTranslator; 60 | 61 | /** 62 | * @return \Illuminate\Translation\Translator 63 | */ 64 | public function getIlluminateTranslator(): Translator 65 | { 66 | if ($this->_illuminateTranslator === null) { 67 | $this->_illuminateTranslator = $this->defaultIlluminateTranslator(); 68 | } 69 | 70 | return $this->_illuminateTranslator; 71 | } 72 | 73 | /** 74 | * @param \Illuminate\Translation\Translator $illuminateTranslator 75 | * @return static self reference. 76 | */ 77 | public function setIlluminateTranslator(Translator $illuminateTranslator): self 78 | { 79 | $this->_illuminateTranslator = $illuminateTranslator; 80 | 81 | return $this; 82 | } 83 | 84 | /** 85 | * @return Translator default Laravel translator. 86 | */ 87 | protected function defaultIlluminateTranslator(): Translator 88 | { 89 | return \Illuminate\Container\Container::getInstance()->make('translator'); 90 | } 91 | 92 | /** 93 | * {@inheritdoc} 94 | */ 95 | public function translate($category, $message, $params, $language): string 96 | { 97 | if (in_array($category, $this->illuminateCategories, true)) { 98 | return $this->getIlluminateTranslator()->get($category.'.'.$message, $params, $language); 99 | } 100 | 101 | return parent::translate($category, $message, $params, $language); 102 | } 103 | 104 | /** 105 | * {@inheritdoc} 106 | */ 107 | public function format($message, $params, $language): string 108 | { 109 | $params = (array) $params; 110 | 111 | $message = parent::format($message, $params, $language); 112 | 113 | return $this->makeReplacements($message, $params); 114 | } 115 | 116 | /** 117 | * Make the Laravel-like place-holder replacements on a translated message. 118 | * It replaces placeholders, marked by ':', which are not processed with original {@see format()} method. 119 | * 120 | * @param string $message raw message. 121 | * @param array $params the parameters that will be used for the replacement. 122 | * @return string the formatted message. 123 | */ 124 | protected function makeReplacements($message, array $params) 125 | { 126 | if (empty($params)) { 127 | return $message; 128 | } 129 | 130 | uksort($params, function ($a, $b) { 131 | if (mb_strlen($a) > mb_strlen($b)) { 132 | return -1; 133 | } 134 | 135 | return 1; 136 | }); 137 | 138 | foreach ($params as $key => $value) { 139 | $message = str_replace( 140 | [':'.$key, ':'.Str::upper($key), ':'.Str::ucfirst($key)], 141 | [$value, Str::upper($value), Str::ucfirst($value)], 142 | $message 143 | ); 144 | } 145 | 146 | return $message; 147 | } 148 | } 149 | -------------------------------------------------------------------------------- /src/Yii/Web/User.php: -------------------------------------------------------------------------------- 1 | [ 26 | * 'user' => Yii2tech\Illuminate\Yii\Web\User::class, 27 | * // ... 28 | * ], 29 | * // ... 30 | * ]; 31 | * ``` 32 | * 33 | * @see \Illuminate\Auth\AuthManager 34 | * 35 | * @property \Illuminate\Auth\AuthManager $illuminateAuthManager related Laravel auth manager. 36 | * 37 | * @author Paul Klimov 38 | * @since 1.0 39 | */ 40 | class User extends \yii\web\User 41 | { 42 | /** 43 | * @var string|null guard to be used while retrieving identity from Laravel auth manager. 44 | */ 45 | public $guard; 46 | 47 | /** 48 | * @var \yii\web\IdentityInterface|bool user identity. 49 | */ 50 | private $_identity = false; 51 | 52 | /** 53 | * @var \Illuminate\Auth\AuthManager related Laravel auth manager. 54 | */ 55 | private $_illuminateAuthManager; 56 | 57 | /** 58 | * {@inheritdoc} 59 | */ 60 | public function getIdentity($autoRenew = true) 61 | { 62 | if ($this->_identity === false) { 63 | $identity = $this->getIlluminateAuthManager()->guard($this->guard)->user(); 64 | if ($identity !== null) { 65 | $identity = $this->convertIlluminateIdentity($identity); 66 | } 67 | 68 | $this->_identity = $identity; 69 | } 70 | 71 | return $this->_identity; 72 | } 73 | 74 | /** 75 | * {@inheritdoc} 76 | */ 77 | public function setIdentity($identity): void 78 | { 79 | parent::setIdentity($identity); 80 | 81 | $this->_identity = $identity; 82 | } 83 | 84 | /** 85 | * @return \Illuminate\Auth\AuthManager 86 | */ 87 | public function getIlluminateAuthManager(): AuthManager 88 | { 89 | if ($this->_illuminateAuthManager === null) { 90 | $this->_illuminateAuthManager = $this->defaultIlluminateAuthManager(); 91 | } 92 | 93 | return $this->_illuminateAuthManager; 94 | } 95 | 96 | /** 97 | * @param \Illuminate\Auth\AuthManager $authManager 98 | * @return static self reference. 99 | */ 100 | public function setIlluminateAuthManager(AuthManager $authManager): self 101 | { 102 | $this->_illuminateAuthManager = $authManager; 103 | 104 | return $this; 105 | } 106 | 107 | /** 108 | * @return \Illuminate\Auth\AuthManager default Laravel auth manager. 109 | */ 110 | protected function defaultIlluminateAuthManager(): AuthManager 111 | { 112 | return Container::getInstance()->make('auth'); 113 | } 114 | 115 | /** 116 | * {@inheritdoc} 117 | */ 118 | public function switchIdentity($identity, $duration = 0): void 119 | { 120 | $this->setIdentity($identity); 121 | 122 | if ($identity === null) { 123 | $this->getIlluminateAuthManager()->guard($this->guard)->logout(); 124 | 125 | return; 126 | } 127 | 128 | if ($identity instanceof BaseActiveRecord) { 129 | $id = $identity->getPrimaryKey(); 130 | } else { 131 | $id = $identity->id; 132 | } 133 | 134 | $this->getIlluminateAuthManager()->guard($this->guard)->loginUsingId($id); 135 | } 136 | 137 | /** 138 | * Converts Laravel identity into Yii one. 139 | * 140 | * @param mixed $identity Laravel identity. 141 | * @return IdentityInterface Yii compatible identity instance. 142 | */ 143 | protected function convertIlluminateIdentity($identity): IdentityInterface 144 | { 145 | if ($identity instanceof Model) { 146 | $id = $identity->getKey(); 147 | $attributes = $identity->getAttributes(); 148 | } elseif ($identity instanceof Authenticatable) { 149 | $id = $identity->getAuthIdentifier(); 150 | $attributes = []; 151 | } elseif (is_array($identity) && isset($identity['id'])) { 152 | $id = $identity['id']; 153 | $attributes = $identity; 154 | } else { 155 | throw new RuntimeException('Unable to convert identity from "'.print_r($identity, true).'"'); 156 | } 157 | 158 | $identityClass = $this->identityClass; 159 | if (! empty($attributes) && is_subclass_of($identityClass, BaseActiveRecord::class)) { 160 | $record = new $identityClass; 161 | call_user_func([$identityClass, 'populateRecord'], $record, $attributes); 162 | 163 | return $record; 164 | } 165 | 166 | return call_user_func([$identityClass, 'findIdentity'], $id); 167 | } 168 | } 169 | -------------------------------------------------------------------------------- /src/Yii/Caching/Cache.php: -------------------------------------------------------------------------------- 1 | [ 23 | * 'cache' => Yii2tech\Illuminate\Yii\Caching\Cache::class, 24 | * // ... 25 | * ], 26 | * // ... 27 | * ]; 28 | * ``` 29 | * 30 | * > Note: by default this component will not allow you to share particular cache keys between Yii and Laravel, 31 | * since Yii uses special prefix for the cache keys and stores data in serialized state. If you wish to share same 32 | * cache key you should disable {@see \yii\caching\Cache::$keyPrefix} and {@see \yii\caching\Cache::$serializer}. 33 | * 34 | * @see \yii\caching\Cache::$keyPrefix 35 | * @see \yii\caching\Cache::$serializer 36 | * @see \Illuminate\Contracts\Cache\Repository 37 | * 38 | * @property \Illuminate\Contracts\Cache\Repository $illuminateCache related Laravel cache repository. 39 | * 40 | * @author Paul Klimov 41 | * @since 1.0 42 | */ 43 | class Cache extends \yii\caching\Cache 44 | { 45 | /** 46 | * @var \Illuminate\Contracts\Cache\Repository related Laravel cache repository. 47 | */ 48 | private $_illuminateCache; 49 | 50 | /** 51 | * @return \Illuminate\Contracts\Cache\Repository 52 | */ 53 | public function getIlluminateCache(): Repository 54 | { 55 | if ($this->_illuminateCache === null) { 56 | $this->_illuminateCache = $this->defaultIlluminateCache(); 57 | } 58 | 59 | return $this->_illuminateCache; 60 | } 61 | 62 | /** 63 | * @param \Illuminate\Contracts\Cache\Repository $illuminateCache 64 | * @return static self reference. 65 | */ 66 | public function setIlluminateCache(Repository $illuminateCache): self 67 | { 68 | $this->_illuminateCache = $illuminateCache; 69 | 70 | return $this; 71 | } 72 | 73 | /** 74 | * @return \Illuminate\Contracts\Cache\Repository default cache repository. 75 | */ 76 | protected function defaultIlluminateCache(): Repository 77 | { 78 | return \Illuminate\Support\Facades\Cache::getFacadeRoot()->store(); 79 | } 80 | 81 | /** 82 | * {@inheritdoc} 83 | */ 84 | protected function getValue($key) 85 | { 86 | return $this->getIlluminateCache()->get($key, false); 87 | } 88 | 89 | /** 90 | * {@inheritdoc} 91 | */ 92 | protected function setValue($key, $value, $duration): bool 93 | { 94 | $this->getIlluminateCache()->put($key, $value, $this->convertDuration($duration)); 95 | 96 | return true; 97 | } 98 | 99 | /** 100 | * {@inheritdoc} 101 | */ 102 | protected function addValue($key, $value, $duration): bool 103 | { 104 | return $this->getIlluminateCache()->add($key, $value, $this->convertDuration($duration)); 105 | } 106 | 107 | /** 108 | * {@inheritdoc} 109 | */ 110 | protected function deleteValue($key): bool 111 | { 112 | return $this->getIlluminateCache()->forget($key); 113 | } 114 | 115 | /** 116 | * {@inheritdoc} 117 | */ 118 | protected function flushValues(): bool 119 | { 120 | return $this->getIlluminateCache()->clear(); 121 | } 122 | 123 | /** 124 | * {@inheritdoc} 125 | */ 126 | protected function getValues($keys) 127 | { 128 | return $this->getIlluminateCache()->getMultiple($keys, false); 129 | } 130 | 131 | /** 132 | * {@inheritdoc} 133 | */ 134 | protected function setValues($data, $duration): array 135 | { 136 | $this->getIlluminateCache()->setMultiple($data, $this->convertDuration($duration)); 137 | 138 | return []; 139 | } 140 | 141 | /** 142 | * {@inheritdoc} 143 | */ 144 | protected function addValues($data, $duration): array 145 | { 146 | $values = $this->multiGet(array_keys($data)); 147 | 148 | $failedKeys = []; 149 | $newValues = []; 150 | 151 | foreach ($values as $key => $value) { 152 | if ($value !== false) { 153 | $failedKeys[] = $key; 154 | continue; 155 | } 156 | 157 | $newValues[$key] = $data[$key]; 158 | } 159 | 160 | $this->setValues($newValues, $duration); 161 | 162 | return $failedKeys; 163 | } 164 | 165 | /** 166 | * Converts cache duration specification from Yii to Laravel. 167 | * 168 | * @param float|int|null $duration cache duration in seconds, zero - means infinite. 169 | * @return float|int|null cache duration in seconds, `null` means infinite. 170 | */ 171 | protected function convertDuration($duration) 172 | { 173 | return $duration == 0 ? null : $duration; 174 | } 175 | } 176 | -------------------------------------------------------------------------------- /src/Yii/Web/Response.php: -------------------------------------------------------------------------------- 1 | [ 26 | * 'response' => Yii2tech\Illuminate\Yii\Web\Response::class, 27 | * // ... 28 | * ], 29 | * // ... 30 | * ]; 31 | * ``` 32 | * 33 | * Usage of this component also allows returning of the response generated by Laravel from Yii controller. For example: 34 | * 35 | * ```php 36 | * class FooController extends \yii\web\Controller 37 | * { 38 | * public function actionFoo() 39 | * { 40 | * // ... 41 | * return Yii::$app->response->setIlluminateResponse(redirect('foo/create')->withInput()); 42 | * } 43 | * } 44 | * ``` 45 | * 46 | * @see \Illuminate\Http\Response 47 | * @see \Yii2tech\Illuminate\Http\YiiApplicationMiddleware 48 | * 49 | * @property \Illuminate\Http\Response $illuminateResponse related Laravel response. 50 | * 51 | * @author Paul Klimov 52 | * @since 1.0 53 | */ 54 | class Response extends \yii\web\Response 55 | { 56 | /** 57 | * @var \Illuminate\Http\Response|null related Laravel response. 58 | */ 59 | private $_illuminateResponse; 60 | 61 | /** 62 | * @param bool $create whether to create a response, if it is empty. 63 | * @return \Illuminate\Http\Response|null 64 | */ 65 | public function getIlluminateResponse(bool $create = false): ?IlluminateResponse 66 | { 67 | if ($create && $this->_illuminateResponse === null) { 68 | $this->_illuminateResponse = $this->createIlluminateResponse(); 69 | } 70 | 71 | return $this->_illuminateResponse; 72 | } 73 | 74 | /** 75 | * @param \Illuminate\Http\Response|null $illuminateResponse 76 | * @return static reference. 77 | */ 78 | public function setIlluminateResponse(?IlluminateResponse $illuminateResponse): self 79 | { 80 | $this->_illuminateResponse = $illuminateResponse; 81 | 82 | return $this; 83 | } 84 | 85 | /** 86 | * Creates default {@see $illuminateResponse} instance. 87 | * 88 | * @return \Illuminate\Http\Response Laravel response instance. 89 | */ 90 | protected function createIlluminateResponse(): IlluminateResponse 91 | { 92 | return \Illuminate\Container\Container::getInstance()->make(IlluminateResponse::class); 93 | } 94 | 95 | /** 96 | * {@inheritdoc} 97 | */ 98 | public function clear(): void 99 | { 100 | parent::clear(); 101 | 102 | $this->setIlluminateResponse(null); 103 | } 104 | 105 | /** 106 | * {@inheritdoc} 107 | */ 108 | public function send(): void 109 | { 110 | if ($this->getIlluminateResponse() !== null) { 111 | $this->isSent = true; 112 | 113 | return; 114 | } 115 | 116 | parent::send(); 117 | } 118 | 119 | /** 120 | * {@inheritdoc} 121 | */ 122 | protected function prepare(): void 123 | { 124 | if ($this->stream === null) { 125 | // avoid usage of response bridge for file sending, since it may cause PHP memory error. 126 | $response = $this->getIlluminateResponse(); 127 | if ($response === null) { 128 | $this->setIlluminateResponse($this->createIlluminateResponse()); 129 | } 130 | } 131 | 132 | parent::prepare(); 133 | } 134 | 135 | /** 136 | * {@inheritdoc} 137 | */ 138 | protected function sendHeaders(): void 139 | { 140 | $response = $this->getIlluminateResponse(); 141 | if ($response === null) { 142 | parent::sendHeaders(); 143 | 144 | return; 145 | } 146 | 147 | if (headers_sent($file, $line)) { 148 | throw new HeadersAlreadySentException($file, $line); 149 | } 150 | 151 | $response->setProtocolVersion($this->version); 152 | $response->setStatusCode($this->getStatusCode(), $this->statusText); 153 | 154 | foreach ($this->getHeaders() as $name => $values) { 155 | $response->headers->set($name, $values); 156 | } 157 | 158 | $this->sendCookies(); 159 | } 160 | 161 | /** 162 | * {@inheritdoc} 163 | */ 164 | protected function sendCookies(): void 165 | { 166 | $response = $this->getIlluminateResponse(); 167 | if ($response === null) { 168 | parent::sendCookies(); 169 | 170 | return; 171 | } 172 | 173 | $request = Yii::$app->getRequest(); 174 | if ($request->enableCookieValidation) { 175 | if ($request->cookieValidationKey == '') { 176 | throw new InvalidConfigException(get_class($request) . '::$cookieValidationKey must be configured with a secret key.'); 177 | } 178 | $validationKey = $request->cookieValidationKey; 179 | } 180 | 181 | foreach ($this->getCookies() as $cookie) { 182 | $value = $cookie->value; 183 | if ($cookie->expire != 1 && isset($validationKey)) { 184 | $value = Yii::$app->getSecurity()->hashData(serialize([$cookie->name, $value]), $validationKey); 185 | } 186 | 187 | $response->headers->setCookie(new Cookie($cookie->name, $value, $cookie->expire, $cookie->path, $cookie->domain, $cookie->secure, $cookie->httpOnly)); 188 | } 189 | } 190 | 191 | /** 192 | * {@inheritdoc} 193 | */ 194 | protected function sendContent(): void 195 | { 196 | $response = $this->getIlluminateResponse(); 197 | if ($response === null) { 198 | parent::sendContent(); 199 | 200 | return; 201 | } 202 | 203 | if ($this->stream === null) { 204 | $response->setContent($this->content); 205 | 206 | return; 207 | } 208 | 209 | ob_start(); 210 | ob_implicit_flush(false); 211 | 212 | try { 213 | parent::sendContent(); 214 | 215 | $response->setContent(ob_get_clean()); 216 | } catch (\Throwable $e) { 217 | if (!@ob_end_clean()) { 218 | ob_clean(); 219 | } 220 | throw $e; 221 | } 222 | } 223 | } 224 | -------------------------------------------------------------------------------- /src/Http/YiiApplicationMiddleware.php: -------------------------------------------------------------------------------- 1 | middleware(Yii2tech\Illuminate\Http\YiiApplicationMiddleware::class) 51 | * ->where('fallbackPlaceholder', '.*') 52 | * ->fallback(); 53 | * ``` 54 | * 55 | * Each middleware instance is automatically configured from the configuration key 'yii.middleware' using [array factory](https://github.com/illuminatech/array-factory). 56 | * 57 | * @see \Illuminatech\ArrayFactory\FactoryContract 58 | * @see \Yii2tech\Illuminate\Yii\Web\Response 59 | * @see DummyResponse 60 | * 61 | * @author Paul Klimov 62 | * @since 1.0 63 | */ 64 | class YiiApplicationMiddleware 65 | { 66 | /** 67 | * @var string default path to Yii application entry script relative to the project base path. 68 | * This value will be used only in case entry script is not specified as a middleware parameter. 69 | */ 70 | public $defaultEntryScript = 'legacy/web/index.php'; 71 | 72 | /** 73 | * @var string|null path to bootstrap file, which should be included before defining constants and including `Yii.php`. 74 | */ 75 | public $bootstrap; 76 | 77 | /** 78 | * @var array|null array configuration for Yii DI container to be applied during Yii bootstrap. 79 | * If not set - container will not be explicitly setup. 80 | * @see FactoryContract::make() 81 | * 82 | * Example: 83 | * 84 | * ```php 85 | * [ 86 | * '__class' => Yii2tech\Illuminate\Yii\Di\Container::class, 87 | * ] 88 | * ``` 89 | */ 90 | public $container; 91 | 92 | /** 93 | * @var array|null array configuration for Yii logger to be applied during Yii bootstrap. 94 | * If not set - logger will not be explicitly setup. 95 | * @see FactoryContract::make() 96 | * 97 | * Example: 98 | * 99 | * ```php 100 | * [ 101 | * '__class' => Yii2tech\Illuminate\Yii\Log\Logger::class, 102 | * ] 103 | * ``` 104 | */ 105 | public $logger; 106 | 107 | /** 108 | * @var bool whether to perform cleanup of Yii application. 109 | */ 110 | public $cleanup = true; 111 | 112 | /** 113 | * @var \Illuminate\Contracts\Foundation\Application Laravel application instance. 114 | */ 115 | protected $app; 116 | 117 | /** 118 | * Constructor. 119 | * 120 | * @param Application $app Laravel application instance. 121 | */ 122 | public function __construct(Application $app) 123 | { 124 | $this->app = $app; 125 | 126 | $this->getFactory()->configure($this, $this->app->get('config')->get('yii.middleware', [])); 127 | } 128 | 129 | /** 130 | * Returns related array factory for components creation and configuration. 131 | * 132 | * @return FactoryContract array factory instance. 133 | */ 134 | public function getFactory(): FactoryContract 135 | { 136 | return $this->app->make(FactoryContract::class); 137 | } 138 | 139 | /** 140 | * Handle an incoming request, attempting to resolve it via Yii web application. 141 | * 142 | * @param \Illuminate\Http\Request $request request to be processed. 143 | * @param \Closure $next next pipeline request handler. 144 | * @param string|null $entryScript path to Yii application entry script relative to the project base path. 145 | * @return mixed 146 | */ 147 | public function handle(Request $request, Closure $next, ?string $entryScript = null) 148 | { 149 | $this->bootstrapYii(); 150 | 151 | try { 152 | return $this->runYii($entryScript); 153 | } catch (YiiHttpException $e) { 154 | $this->cleanup(); 155 | 156 | if ($e->statusCode == 404) { 157 | // If Yii indicates page does not exist - pass its resolving to Laravel 158 | return $next($request); 159 | } 160 | 161 | throw new HttpException($e->statusCode, $e->getMessage(), $e, [], $e->getCode()); 162 | } catch (YiiExitException $e) { 163 | // In case Yii requests application termination - request is considered as handled 164 | return $this->createResponse(); 165 | } 166 | } 167 | 168 | /** 169 | * Makes preparations for Yii application run. 170 | */ 171 | protected function bootstrapYii() 172 | { 173 | if ($this->bootstrap) { 174 | require $this->bootstrap; 175 | } 176 | 177 | defined('YII_ENABLE_ERROR_HANDLER') or define('YII_ENABLE_ERROR_HANDLER', false); 178 | 179 | defined('YII_DEBUG') or define('YII_DEBUG', $this->app->get('config')->get('app.debug', false)); 180 | 181 | if (! defined('YII_ENV')) { 182 | $environment = $this->app->get('config')->get('app.env', 'production'); 183 | switch ($environment) { 184 | case 'production': 185 | $environment = 'prod'; 186 | break; 187 | case 'local': 188 | case 'development': 189 | $environment = 'dev'; 190 | break; 191 | case 'testing': 192 | $environment = 'test'; 193 | break; 194 | } 195 | 196 | define('YII_ENV', $environment); 197 | } 198 | 199 | if (! class_exists('Yii')) { 200 | require $this->app->make('path.base').'/vendor/yiisoft/yii2/Yii.php'; 201 | } 202 | 203 | if ($this->container) { 204 | Yii::$container = $this->getFactory()->make($this->container); 205 | } 206 | 207 | if ($this->logger) { 208 | Yii::setLogger($this->getFactory()->make($this->logger)); 209 | } 210 | } 211 | 212 | /** 213 | * Runs Yii application from the given entry PHP script. 214 | * 215 | * @param string|null $entryScript path to Yii application entry script relative to the project base path. 216 | * @return \Illuminate\Http\Response HTTP response instance. 217 | */ 218 | protected function runYii(?string $entryScript = null): Response 219 | { 220 | if ($entryScript === null) { 221 | $entryScript = $this->defaultEntryScript; 222 | } 223 | 224 | $entryScript = $this->app->make('path.base').DIRECTORY_SEPARATOR.$entryScript; 225 | 226 | require $entryScript; 227 | 228 | return $this->createResponse(); 229 | } 230 | 231 | /** 232 | * Performs clean up after running Yii application in case {@see $cleanup} is enabled. 233 | */ 234 | protected function cleanup() 235 | { 236 | if ($this->cleanup) { 237 | $this->terminateYii(); 238 | } 239 | } 240 | 241 | /** 242 | * Preforms clean up after running Yii application. 243 | */ 244 | protected function terminateYii() 245 | { 246 | Yii::$classMap = []; 247 | Yii::$aliases = []; 248 | 249 | Yii::setLogger(null); 250 | Yii::$app = null; 251 | Yii::$container = null; 252 | } 253 | 254 | /** 255 | * Creates HTTP response for this middleware. 256 | * In case Yii application uses response, which allows its conversion into Laravel one, such conversion will be perfromed. 257 | * Otherwise a dummy response will be generated. 258 | * This method performs automatic clean up. 259 | * 260 | * @see \Yii2tech\Illuminate\Yii\Web\Response 261 | * @see DummyResponse 262 | * 263 | * @return \Illuminate\Http\Response HTTP response instance. 264 | */ 265 | protected function createResponse(): Response 266 | { 267 | if (headers_sent()) { 268 | $this->cleanup(); 269 | 270 | return new DummyResponse(); 271 | } 272 | 273 | $yiiResponse = Yii::$app ? Yii::$app->get('response') : null; 274 | 275 | $this->cleanup(); 276 | 277 | if ($yiiResponse instanceof \Yii2tech\Illuminate\Yii\Web\Response) { 278 | return $yiiResponse->getIlluminateResponse(true); 279 | } 280 | 281 | return new DummyResponse(); 282 | } 283 | } 284 | -------------------------------------------------------------------------------- /src/Yii/Web/Request.php: -------------------------------------------------------------------------------- 1 | [ 26 | * 'request' => [ 27 | * 'class' => Yii2tech\Illuminate\Yii\Web\Request::class, 28 | * ], 29 | * // ... 30 | * ], 31 | * // ... 32 | * ]; 33 | * ``` 34 | * 35 | * @see \Illuminate\Http\Request 36 | * 37 | * @author Paul Klimov 38 | * @since 1.0 39 | */ 40 | class Request extends \yii\web\Request 41 | { 42 | /** 43 | * {@inheritdoc} 44 | */ 45 | public $csrfParam = '_token'; 46 | 47 | /** 48 | * @var bool whether to use CSRF generation/validation supplied by Laravel. 49 | * If enabled make sure {@see $csrfParam} is set to '_token'. 50 | */ 51 | public $useIlluminateCsrfValildation = false; 52 | 53 | /** 54 | * @var \Illuminate\Http\Request related Laravel HTTP request. 55 | */ 56 | private $_illuminateRequest; 57 | 58 | /** 59 | * @var \yii\web\HeaderCollection request headers. 60 | */ 61 | private $_headers; 62 | 63 | /** 64 | * @var string raw body content. 65 | */ 66 | private $_rawBody; 67 | 68 | /** 69 | * @var array|null the request body parameters. 70 | */ 71 | private $_bodyParams; 72 | 73 | /** 74 | * @return \Illuminate\Http\Request 75 | */ 76 | public function getIlluminateRequest(): IlluminateRequest 77 | { 78 | if ($this->_illuminateRequest === null) { 79 | $this->_illuminateRequest = $this->defaultIlluminateRequest(); 80 | } 81 | 82 | return $this->_illuminateRequest; 83 | } 84 | 85 | /** 86 | * @param \Illuminate\Http\Request $illuminateRequest 87 | * @return static self reference. 88 | */ 89 | public function setIlluminateRequest(IlluminateRequest $illuminateRequest): self 90 | { 91 | $this->_illuminateRequest = $illuminateRequest; 92 | 93 | return $this; 94 | } 95 | 96 | /** 97 | * @return \Illuminate\Http\Request default related Laravel HTTP request. 98 | */ 99 | protected function defaultIlluminateRequest(): IlluminateRequest 100 | { 101 | return \Illuminate\Container\Container::getInstance()->make('request'); 102 | } 103 | 104 | /** 105 | * {@inheritdoc} 106 | */ 107 | public function getHeaders() 108 | { 109 | if ($this->_headers === null) { 110 | $this->_headers = new HeaderCollection(); 111 | foreach ($this->getIlluminateRequest()->headers->all() as $name => $values) { 112 | $this->_headers->set($name, $values); 113 | } 114 | } 115 | 116 | return $this->_headers; 117 | } 118 | 119 | /** 120 | * {@inheritdoc} 121 | */ 122 | public function getMethod(): string 123 | { 124 | return $this->getIlluminateRequest()->getMethod(); 125 | } 126 | 127 | /** 128 | * {@inheritdoc} 129 | */ 130 | public function getRawBody() 131 | { 132 | if ($this->_rawBody === null) { 133 | $this->_rawBody = $this->getIlluminateRequest()->getContent(); 134 | } 135 | 136 | return $this->_rawBody; 137 | } 138 | 139 | /** 140 | * {@inheritdoc} 141 | */ 142 | public function setRawBody($rawBody): void 143 | { 144 | $this->_rawBody = $rawBody; 145 | } 146 | 147 | /** 148 | * {@inheritdoc} 149 | */ 150 | public function getBodyParams() 151 | { 152 | if ($this->_bodyParams === null) { 153 | $illuminateRequest = $this->getIlluminateRequest(); 154 | if ($illuminateRequest->isJson()) { 155 | $this->_bodyParams = $illuminateRequest->json()->all(); 156 | } elseif ($this->getContentType() === 'application/x-www-form-urlencoded') { 157 | $this->_bodyParams = $illuminateRequest->request->all(); 158 | } else { 159 | $this->_bodyParams = parent::getBodyParams(); 160 | } 161 | } 162 | 163 | return $this->_bodyParams; 164 | } 165 | 166 | /** 167 | * {@inheritdoc} 168 | */ 169 | public function setBodyParams($values) 170 | { 171 | $this->_bodyParams = $values; 172 | } 173 | 174 | /** 175 | * {@inheritdoc} 176 | * @since 1.1.2 177 | */ 178 | public function getScriptUrl() 179 | { 180 | try { 181 | return parent::getScriptUrl(); 182 | } catch (InvalidConfigException $e) { 183 | // Illuminate request does not provide script URL, thus set up a mock, if Yii fails to determine it 184 | $this->setScriptUrl('/index.php'); 185 | } 186 | 187 | return parent::getScriptUrl(); 188 | } 189 | 190 | /** 191 | * {@inheritdoc} 192 | * @since 1.1.2 193 | */ 194 | protected function resolveRequestUri() 195 | { 196 | return $this->getIlluminateRequest()->getRequestUri(); 197 | } 198 | 199 | /** 200 | * {@inheritdoc} 201 | */ 202 | protected function loadCookies() 203 | { 204 | $cookies = []; 205 | if ($this->enableCookieValidation) { 206 | if ($this->cookieValidationKey == '') { 207 | throw new InvalidConfigException(get_class($this) . '::$cookieValidationKey must be configured with a secret key.'); 208 | } 209 | foreach ($this->getIlluminateRequest()->cookies as $name => $value) { 210 | if (! is_string($value)) { 211 | continue; 212 | } 213 | $data = Yii::$app->getSecurity()->validateData($value, $this->cookieValidationKey); 214 | if ($data === false) { 215 | continue; 216 | } 217 | $data = @unserialize($data); 218 | if (is_array($data) && isset($data[0], $data[1]) && $data[0] === $name) { 219 | $cookies[$name] = Yii::createObject([ 220 | 'class' => \yii\web\Cookie::class, 221 | 'name' => $name, 222 | 'value' => $data[1], 223 | 'expire' => null, 224 | ]); 225 | } 226 | } 227 | } else { 228 | foreach ($this->getIlluminateRequest()->cookies as $name => $value) { 229 | $cookies[$name] = Yii::createObject([ 230 | 'class' => \yii\web\Cookie::class, 231 | 'name' => $name, 232 | 'value' => $value, 233 | 'expire' => null, 234 | ]); 235 | } 236 | } 237 | 238 | return $cookies; 239 | } 240 | 241 | /** 242 | * {@inheritdoc} 243 | */ 244 | public function getCsrfToken($regenerate = false) 245 | { 246 | if (! $this->useIlluminateCsrfValildation) { 247 | return parent::getCsrfToken($regenerate); 248 | } 249 | 250 | if ($regenerate) { 251 | return $this->generateCsrfToken(); 252 | } 253 | 254 | return $this->loadCsrfToken(); 255 | } 256 | 257 | /** 258 | * {@inheritdoc} 259 | */ 260 | protected function loadCsrfToken() 261 | { 262 | if (! $this->useIlluminateCsrfValildation) { 263 | return parent::loadCsrfToken(); 264 | } 265 | 266 | return $this->getIlluminateRequest()->session()->token(); 267 | } 268 | 269 | /** 270 | * {@inheritdoc} 271 | */ 272 | protected function generateCsrfToken() 273 | { 274 | if (! $this->useIlluminateCsrfValildation) { 275 | return parent::generateCsrfToken(); 276 | } 277 | 278 | $session = $this->getIlluminateRequest()->session(); 279 | $session->regenerateToken(); 280 | 281 | return $session->token(); 282 | } 283 | 284 | /** 285 | * {@inheritdoc} 286 | */ 287 | public function validateCsrfToken($clientSuppliedToken = null) 288 | { 289 | if (! $this->useIlluminateCsrfValildation) { 290 | return parent::validateCsrfToken($clientSuppliedToken); 291 | } 292 | 293 | $method = $this->getMethod(); 294 | // only validate CSRF token on non-"safe" methods https://tools.ietf.org/html/rfc2616#section-9.1.1 295 | if (!$this->enableCsrfValidation || in_array($method, ['GET', 'HEAD', 'OPTIONS'], true)) { 296 | return true; 297 | } 298 | 299 | $trueToken = $this->getCsrfToken(); 300 | 301 | if ($clientSuppliedToken !== null) { 302 | return $this->validateCsrfTokenInternal($clientSuppliedToken, $trueToken); 303 | } 304 | 305 | return $this->validateCsrfTokenInternal($this->getBodyParam($this->csrfParam), $trueToken) 306 | || $this->validateCsrfTokenInternal($this->getCsrfTokenFromHeader(), $trueToken); 307 | } 308 | 309 | /** 310 | * Validates CSRF token. 311 | * @see \Illuminate\Foundation\Http\Middleware\VerifyCsrfToken::tokensMatch() 312 | * 313 | * @param string $clientSuppliedToken The masked client-supplied token. 314 | * @param string $trueToken The masked true token. 315 | * @return bool 316 | */ 317 | private function validateCsrfTokenInternal($clientSuppliedToken, $trueToken): bool 318 | { 319 | if (! is_string($clientSuppliedToken)) { 320 | return false; 321 | } 322 | 323 | return hash_equals($trueToken, $clientSuppliedToken); 324 | } 325 | 326 | /** 327 | * Get all of the input and files for the request. 328 | * 329 | * @param array|null $keys input keys to retrieve, `null` means all input. 330 | * @return array input data. 331 | */ 332 | public function all($keys = null): array 333 | { 334 | return $this->getIlluminateRequest()->all($keys); 335 | } 336 | 337 | /** 338 | * Runs Laravel validation on request data. 339 | * @see \Illuminate\Foundation\Providers\FoundationServiceProvider::registerRequestValidation() 340 | * @see \Illuminate\Validation\Factory::validate() 341 | * 342 | * @param array $rules validation rules. 343 | * @param array $messages error messages. 344 | * @param array $customAttributes 345 | * @return array validated data. 346 | * 347 | * @throws \Illuminate\Validation\ValidationException if validation fails. 348 | */ 349 | public function validate(array $rules, array $messages = [], array $customAttributes = []): array 350 | { 351 | return $this->getIlluminateRequest()->validate($rules, $messages, $customAttributes); 352 | } 353 | } 354 | -------------------------------------------------------------------------------- /src/Yii/Web/Session.php: -------------------------------------------------------------------------------- 1 | [ 25 | * 'session' => Yii2tech\Illuminate\Yii\Web\Session::class, 26 | * // ... 27 | * ], 28 | * // ... 29 | * ]; 30 | * ``` 31 | * 32 | * > Note: usage of this component requires Yii application running within {@see \Illuminate\Session\Middleware\StartSession} middleware. 33 | * 34 | * @see \Illuminate\Session\Store 35 | * 36 | * @property \Illuminate\Session\Store $illuminateSession related Laravel session instance. 37 | * 38 | * @author Paul Klimov 39 | * @since 1.0 40 | */ 41 | class Session extends \yii\web\Session 42 | { 43 | /** 44 | * {@inheritdoc} 45 | */ 46 | public $flashParam = '__yii_flash'; 47 | 48 | /** 49 | * @var \Illuminate\Session\Store 50 | */ 51 | private $_illuminateSession; 52 | 53 | /** 54 | * @return \Illuminate\Session\Store Laravel session store. 55 | */ 56 | public function getIlluminateSession(): Store 57 | { 58 | if ($this->_illuminateSession === null) { 59 | $this->_illuminateSession = $this->defaultIlluminateSession(); 60 | } 61 | 62 | return $this->_illuminateSession; 63 | } 64 | 65 | /** 66 | * @param \Illuminate\Session\Store $session Laravel session store. 67 | * @return static self reference. 68 | */ 69 | public function setIlluminateSession(Store $session): self 70 | { 71 | $this->_illuminateSession = $session; 72 | 73 | return $this; 74 | } 75 | 76 | /** 77 | * @return Store session store instance. 78 | */ 79 | protected function defaultIlluminateSession(): Store 80 | { 81 | return \Illuminate\Support\Facades\Session::getFacadeRoot()->driver(); 82 | } 83 | 84 | /** 85 | * {@inheritdoc} 86 | */ 87 | public function init(): void 88 | { 89 | Component::init(); // skip parent init, avoiding `register_shutdown_function()` call. 90 | } 91 | 92 | /** 93 | * {@inheritdoc} 94 | */ 95 | public function open(): void 96 | { 97 | if ($this->getIsActive()) { 98 | return; 99 | } 100 | 101 | $this->getIlluminateSession()->start(); 102 | } 103 | 104 | /** 105 | * {@inheritdoc} 106 | */ 107 | public function close(): void 108 | { 109 | if ($this->getIsActive()) { 110 | $this->getIlluminateSession()->save(); 111 | } 112 | } 113 | 114 | /** 115 | * {@inheritdoc} 116 | */ 117 | public function destroy(): void 118 | { 119 | if ($this->getIsActive()) { 120 | $this->getIlluminateSession()->invalidate(); 121 | } 122 | } 123 | 124 | /** 125 | * {@inheritdoc} 126 | */ 127 | public function getIsActive(): bool 128 | { 129 | return $this->getIlluminateSession()->isStarted(); 130 | } 131 | 132 | /** 133 | * {@inheritdoc} 134 | */ 135 | public function getId() 136 | { 137 | return $this->getIlluminateSession()->getId(); 138 | } 139 | 140 | /** 141 | * {@inheritdoc} 142 | */ 143 | public function setId($value): void 144 | { 145 | $this->getIlluminateSession()->setId($value); 146 | } 147 | 148 | /** 149 | * {@inheritdoc} 150 | */ 151 | public function regenerateID($deleteOldSession = false): void 152 | { 153 | if ($this->getIsActive()) { 154 | $this->getIlluminateSession()->regenerate($deleteOldSession); 155 | } 156 | } 157 | 158 | /** 159 | * {@inheritdoc} 160 | */ 161 | public function getName() 162 | { 163 | return $this->getIlluminateSession()->getName(); 164 | } 165 | 166 | /** 167 | * {@inheritdoc} 168 | */ 169 | public function setName($value): void 170 | { 171 | $this->getIlluminateSession()->setName($value); 172 | } 173 | 174 | /** 175 | * {@inheritdoc} 176 | */ 177 | public function getIterator() 178 | { 179 | $this->open(); 180 | 181 | return new ArrayIterator($this->getIlluminateSession()->all()); 182 | } 183 | 184 | /** 185 | * {@inheritdoc} 186 | */ 187 | public function getCount(): int 188 | { 189 | $this->open(); 190 | 191 | return count($this->getIlluminateSession()->all()); 192 | } 193 | 194 | /** 195 | * {@inheritdoc} 196 | */ 197 | public function get($key, $defaultValue = null) 198 | { 199 | $this->open(); 200 | 201 | return $this->getIlluminateSession()->get($key, $defaultValue); 202 | } 203 | 204 | /** 205 | * {@inheritdoc} 206 | */ 207 | public function set($key, $value) 208 | { 209 | $this->open(); 210 | 211 | $this->getIlluminateSession()->put($key, $value); 212 | } 213 | 214 | /** 215 | * {@inheritdoc} 216 | */ 217 | public function remove($key) 218 | { 219 | $this->open(); 220 | 221 | return $this->getIlluminateSession()->pull($key); 222 | } 223 | 224 | /** 225 | * {@inheritdoc} 226 | */ 227 | public function removeAll(): void 228 | { 229 | $this->open(); 230 | $this->getIlluminateSession()->flush(); 231 | } 232 | 233 | /** 234 | * {@inheritdoc} 235 | */ 236 | public function has($key): bool 237 | { 238 | $this->open(); 239 | 240 | return $this->getIlluminateSession()->has($key); 241 | } 242 | 243 | // Flash : 244 | 245 | /** 246 | * {@inheritdoc} 247 | */ 248 | protected function updateFlashCounters(): void 249 | { 250 | $counters = $this->get($this->flashParam, []); 251 | if (is_array($counters)) { 252 | foreach ($counters as $key => $count) { 253 | if ($count > 0) { 254 | unset($counters[$key]); 255 | $this->remove($key); 256 | } elseif ($count == 0) { 257 | $counters[$key]++; 258 | } 259 | } 260 | $this->set($this->flashParam, $counters); 261 | } else { 262 | // fix the unexpected problem that flashParam doesn't return an array 263 | $this->remove($this->flashParam); 264 | } 265 | } 266 | 267 | /** 268 | * {@inheritdoc} 269 | */ 270 | public function getFlash($key, $defaultValue = null, $delete = false) 271 | { 272 | $counters = $this->get($this->flashParam, []); 273 | if (isset($counters[$key])) { 274 | $value = $this->get($key, $defaultValue); 275 | if ($delete) { 276 | $this->removeFlash($key); 277 | } elseif ($counters[$key] < 0) { 278 | // mark for deletion in the next request 279 | $counters[$key] = 1; 280 | $this->set($this->flashParam, $counters); 281 | } 282 | 283 | return $value; 284 | } 285 | 286 | return $defaultValue; 287 | } 288 | 289 | /** 290 | * {@inheritdoc} 291 | */ 292 | public function getAllFlashes($delete = false): array 293 | { 294 | $counters = $this->get($this->flashParam, []); 295 | $flashes = []; 296 | 297 | $session = $this->getIlluminateSession()->all(); 298 | 299 | foreach (array_keys($counters) as $key) { 300 | if (array_key_exists($key, $session)) { 301 | $flashes[$key] = $session[$key]; 302 | if ($delete) { 303 | unset($counters[$key], $session[$key]); 304 | $this->remove($key); 305 | } elseif ($counters[$key] < 0) { 306 | // mark for deletion in the next request 307 | $counters[$key] = 1; 308 | } 309 | } else { 310 | unset($counters[$key]); 311 | } 312 | } 313 | 314 | $this->set($this->flashParam, $counters); 315 | 316 | return $flashes; 317 | } 318 | 319 | /** 320 | * {@inheritdoc} 321 | */ 322 | public function setFlash($key, $value = true, $removeAfterAccess = true): void 323 | { 324 | $counters = $this->get($this->flashParam, []); 325 | $counters[$key] = $removeAfterAccess ? -1 : 0; 326 | 327 | $this->set($key, $value); 328 | $this->set($this->flashParam, $counters); 329 | } 330 | 331 | /** 332 | * {@inheritdoc} 333 | */ 334 | public function addFlash($key, $value = true, $removeAfterAccess = true): void 335 | { 336 | $counters = $this->get($this->flashParam, []); 337 | $counters[$key] = $removeAfterAccess ? -1 : 0; 338 | 339 | $this->set($this->flashParam, $counters); 340 | $session = $this->getIlluminateSession()->all(); 341 | 342 | if (empty($session[$key])) { 343 | $session[$key] = [$value]; 344 | } elseif (is_array($session[$key])) { 345 | $session[$key][] = $value; 346 | } else { 347 | $session[$key] = [$session[$key], $value]; 348 | } 349 | 350 | $this->set($key, $session[$key]); 351 | } 352 | 353 | /** 354 | * {@inheritdoc} 355 | */ 356 | public function removeFlash($key) 357 | { 358 | $counters = $this->get($this->flashParam, []); 359 | $session = $this->getIlluminateSession()->all(); 360 | $value = isset($session[$key], $counters[$key]) ? $session[$key] : null; 361 | unset($counters[$key]); 362 | $this->remove($key); 363 | $this->set($this->flashParam, $counters); 364 | 365 | return $value; 366 | } 367 | 368 | /** 369 | * {@inheritdoc} 370 | */ 371 | public function removeAllFlashes(): void 372 | { 373 | $counters = $this->get($this->flashParam, []); 374 | foreach (array_keys($counters) as $key) { 375 | $this->remove($key); 376 | } 377 | $this->remove($this->flashParam); 378 | } 379 | 380 | /** 381 | * {@inheritdoc} 382 | */ 383 | public function hasFlash($key): bool 384 | { 385 | return $this->getFlash($key) !== null; 386 | } 387 | 388 | // ArrayAccess : 389 | 390 | /** 391 | * {@inheritdoc} 392 | */ 393 | public function offsetExists($offset) 394 | { 395 | $this->open(); 396 | $session = $this->getIlluminateSession()->all(); 397 | 398 | return isset($session[$offset]); 399 | } 400 | 401 | /** 402 | * {@inheritdoc} 403 | */ 404 | public function offsetGet($offset) 405 | { 406 | $this->open(); 407 | 408 | return $this->getIlluminateSession()->get($offset); 409 | } 410 | 411 | /** 412 | * {@inheritdoc} 413 | */ 414 | public function offsetSet($offset, $item) 415 | { 416 | $this->open(); 417 | 418 | $this->getIlluminateSession()->put($offset, $item); 419 | } 420 | 421 | /** 422 | * {@inheritdoc} 423 | */ 424 | public function offsetUnset($offset) 425 | { 426 | $this->open(); 427 | 428 | $this->getIlluminateSession()->forget($offset); 429 | } 430 | } 431 | --------------------------------------------------------------------------------