Skip to content

Commit

Permalink
improve list controller properties to be compatible with 5.1~5.8
Browse files Browse the repository at this point in the history
  • Loading branch information
hhxsv5 committed Jul 5, 2019
1 parent 332cce7 commit b3eb758
Show file tree
Hide file tree
Showing 7 changed files with 151 additions and 171 deletions.
5 changes: 5 additions & 0 deletions KnownIssues-CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,11 @@ class TestController extends Controller

1.避免在构造函数中初始化`请求级`的数据,应在具体`Action`中读取,这样编码风格更合理,建议这样写。

```bash
# 列出你的路由中所有关联的控制器的所有属性
php artisan laravels:list-properties
```

```php
namespace App\Http\Controllers;
class TestController extends Controller
Expand Down
5 changes: 5 additions & 0 deletions KnownIssues.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,11 @@ class TestController extends Controller

1.Avoid initializing `request-level` data in the constructor, which should be read in the concrete `Action`. This coding style is more reasonable, it is recommended to do so.

```bash
# List all properties of all controllers related your routes.
php artisan laravels:list-properties
```

```php
namespace App\Http\Controllers;
class TestController extends Controller
Expand Down
6 changes: 0 additions & 6 deletions README-CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -1027,12 +1027,6 @@ class WorkerStartEvent implements WorkerStartInterface
- 如果你的项目中使用到了Session、Authentication、JWT,请根据情况解除`laravels.php``cleaners`的注释。
- 在 LaravelS 中,所有控制器都是单例,控制器里面设置的属性在请求结束后也会保留下来,在后续请求中都可以获取到之前请求设置的属性,这在大部分情况都不是我们想要的效果。如果想要迁移到 LaravelS,或者找出潜在的问题,可以使用下面的命令。它可以列出你的路由中所有关联的控制器的所有属性:
```bash
php artisan laravels:list-properties
```
- 常见的解决方案:
1. 写一个`XxxCleaner`类来清理单例对象状态,此类需实现接口`Hhxsv5\LaravelS\Illuminate\Cleaners\CleanerInterface`,然后注册到`laravels.php``cleaners`中。
Expand Down
6 changes: 0 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -1011,12 +1011,6 @@ class WorkerStartEvent implements WorkerStartInterface
- Under FPM mode, singleton instances will be instantiated and recycled in every request, request start=>instantiate instance=>request end=>recycled instance.
- Under Swoole Server, All singleton instances will be held in memory, different lifetime from FPM, request start=>instantiate instance=>request end=>do not recycle singleton instance. So need developer to maintain status of singleton instances in every request.
- All controllers are singleton in LaravelS, the properties defined in controllers will be retained after the request is finished. This is not what we want in most cases. If you want to migrate to LaravelS, or find out potential problems, you can use the command below, it can list all properties of all controllers related your routes.
```bash
php artisan laravels:list-properties
```
- If Session/Authentication/JWT is used in your project, please uncomment the `cleaners` in `laravels.php` as appropriate.
Expand Down
158 changes: 0 additions & 158 deletions src/Console/ListPropertiesCommand.php

This file was deleted.

1 change: 0 additions & 1 deletion src/Illuminate/LaravelSServiceProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

namespace Hhxsv5\LaravelS\Illuminate;

use Hhxsv5\LaravelS\Console\ListPropertiesCommand;
use Illuminate\Support\ServiceProvider;

class LaravelSServiceProvider extends ServiceProvider
Expand Down
141 changes: 141 additions & 0 deletions src/Illuminate/ListPropertiesCommand.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
<?php

namespace Hhxsv5\LaravelS\Illuminate;

use Illuminate\Console\Command;

/**
* This command is writing for those who want to know if there's any controller properties defined.
* As controller is a singleton in laravel-s, all properties defined in controller will be retained after the request is finished.
* So if you want to migrate to laravel-s, or just debug your app to find out potential problems, you can try this.
*/
class ListPropertiesCommand extends Command
{
public $signature = 'laravels:list-properties';

public $description = 'List all properties of all controllers.';

/**
* @throws \ReflectionException
*/
public function fire()
{
return $this->handle();
}

/**
* @throws \ReflectionException
*/
public function handle()
{
$this->outputTable();
}

/**
* Output all properties of all controllers as table.
*
* @throws \ReflectionException
*/
private function outputTable()
{
$allProperties = $this->allControllerProperties();
foreach ($allProperties as $controller => $properties) {
if (empty($properties)) {
continue;
}

$this->table(
['Controller', 'Property', 'Property Modifier'],
$properties
);
}
}

/**
* Get all properties of all controllers.
*
* @return array
* @throws \ReflectionException
*/
private function allControllerProperties()
{
$controllers = $this->allControllers();
array_walk($controllers, function (&$properties, $controller) {
$properties = [];
// Get parent's properties
$parent = get_parent_class($controller);
if ($parent) {
$reflectParentController = new \ReflectionClass($parent);
$parentProperties = $reflectParentController->getProperties();
foreach ($parentProperties as $property) {
$properties[$property->getName()] = [
$controller => $controller,
'Property' => $property->getName(),
'Property Modifier' => $this->resolveModifiers($property),
];
}
}

// Get sub controller's properties, override the parent properties.
$reflectController = new \ReflectionClass($controller);
$subProperties = $reflectController->getProperties();
foreach ($subProperties as $property) {
$properties[$property->getName()] = [
$controller => $controller,
'Property' => $property->getName(),
'Property Modifier' => $this->resolveModifiers($property),
];
}
});
return $controllers;
}

/**
* Get all controllers
*
* @return array
* @throws \ReflectionException
*/
private function allControllers()
{
$controllers = [];
$router = isset(app()->router) ? app()->router : (app()->offsetExists('router') ? app('router') : app());
$routes = $router->getRoutes();
if (is_array($routes)) {
$uses = array_column(array_column($routes, 'action'), 'uses');
} else {
$property = new \ReflectionProperty(get_class($routes), 'actionList');
$property->setAccessible(true);
$uses = array_keys($property->getValue($routes));
}

foreach ($uses as $use) {
list($controller,) = explode('@', $use);
$controllers[$controller] = $controller;
}
return $controllers;
}

/**
* Resolve modifiers from \ReflectionProperty
*
* @param \ReflectionProperty $property
* @return string
*/
private function resolveModifiers(\ReflectionProperty $property)
{
if ($property->isPublic()) {
$modifier = 'public';
} elseif ($property->isProtected()) {
$modifier = 'protected';
} elseif ($property->isPrivate()) {
$modifier = 'private';
} else {
$modifier = ' ';
}
if ($property->isStatic()) {
$modifier .= ' static';
}
return $modifier;
}
}

0 comments on commit b3eb758

Please sign in to comment.