Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

support convert path and namespace from composer psr-4 autoload rules #328

Merged
merged 6 commits into from Aug 5, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
6 changes: 0 additions & 6 deletions .travis.yml
Expand Up @@ -10,20 +10,14 @@ matrix:
include:
- php: 7.2
env: SW_VERSION="4.3.6"
- php: 7.2
env: SW_VERSION="4.4.2"
- php: 7.2
env: SW_VERSION="4.4.3"
- php: 7.3
env: SW_VERSION="4.3.6"
- php: 7.3
env: SW_VERSION="4.4.2"
- php: 7.3
env: SW_VERSION="4.4.3"
- php: master
env: SW_VERSION="4.3.6"
- php: master
env: SW_VERSION="4.4.2"
- php: master
env: SW_VERSION="4.4.3"

Expand Down
1 change: 1 addition & 0 deletions CHANGELOG.md
Expand Up @@ -8,6 +8,7 @@
## Changed

- [#330](https://github.com/hyperf-cloud/hyperf/pull/330) Hidden DI scan message when paths is empty.
- [#328](https://github.com/hyperf-cloud/hyperf/pull/328) Support convert path and namespace from composer psr-4 autoload rules.

## Fixed

Expand Down
1 change: 1 addition & 0 deletions composer.json
Expand Up @@ -10,6 +10,7 @@
"support": {},
"require": {
"php": ">=7.2",
"ext-json": "*",
"bandwidth-throttle/token-bucket": "^2.0",
"doctrine/annotations": "^1.6",
"doctrine/inflector": "^1.3",
Expand Down
7 changes: 4 additions & 3 deletions src/database/src/Commands/ModelCommand.php
Expand Up @@ -18,6 +18,7 @@
use Hyperf\Database\ConnectionResolverInterface;
use Hyperf\Database\Model\Model;
use Hyperf\Database\Schema\MySqlBuilder;
use Hyperf\Utils\CodeGen\Project;
use Hyperf\Utils\Str;
use PhpParser\NodeTraverser;
use PhpParser\ParserFactory;
Expand Down Expand Up @@ -140,10 +141,10 @@ protected function createModel(string $table, ModelOption $option)
$table = Str::replaceFirst($option->getPrefix(), '', $table);
$columns = $builder->getColumnTypeListing($table);

$class = $option->getPath() . '/' . Str::studly($table);
$path = BASE_PATH . '/' . $class . '.php';
$project = new Project();
$class = $project->namespace($option->getPath()) . Str::studly($table);
$path = BASE_PATH . '/' . $project->path($class);

$class = str_replace('/', '\\', Str::ucfirst($class));
if (! file_exists($path)) {
$dir = dirname($path);
if (! is_dir($dir)) {
Expand Down
4 changes: 3 additions & 1 deletion src/devtool/src/Generator/GeneratorCommand.php
Expand Up @@ -15,6 +15,7 @@
use Hyperf\Contract\ConfigInterface;
use Hyperf\Utils\ApplicationContext;
use Hyperf\Utils\Arr;
use Hyperf\Utils\CodeGen\Project;
use Hyperf\Utils\Str;
use Psr\Container\ContainerInterface;
use Symfony\Component\Console\Command\Command;
Expand Down Expand Up @@ -117,7 +118,8 @@ protected function alreadyExists($rawName)
*/
protected function getPath($name)
{
return BASE_PATH . '/' . str_replace('\\', '/', lcfirst($name)) . '.php';
$project = new Project();
return BASE_PATH . '/' . $project->path($name);
}

/**
Expand Down
61 changes: 61 additions & 0 deletions src/utils/src/CodeGen/Project.php
@@ -0,0 +1,61 @@
<?php

declare(strict_types=1);
/**
* This file is part of Hyperf.
*
* @link https://www.hyperf.io
* @document https://doc.hyperf.io
* @contact group@hyperf.io
* @license https://github.com/hyperf-cloud/hyperf/blob/master/LICENSE
*/

namespace Hyperf\Utils\CodeGen;

use Hyperf\Utils\Composer;
use Hyperf\Utils\Str;

/**
* Read composer.json autoload psr-4 rules to figure out the namespace or path.
*/
class Project
{
public function namespace(string $path): string
{
$ext = pathinfo($path, PATHINFO_EXTENSION);
if ($ext !== '') {
$path = substr($path, 0, -(strlen($ext) + 1));
} else {
$path = trim($path, '/') . '/';
}
foreach ($this->getAutoloadRules() as $prefix => $prefixPath) {
if (strpos($path, $prefixPath) === 0) {
return $prefix . str_replace('/', '\\', substr($path, strlen($prefixPath)));
}
}
throw new \RuntimeException("Invalid project path: {$path}");
}

public function className(string $path): string
{
return $this->namespace($path);
}

public function path(string $name, $extension = '.php'): string
{
if (Str::endsWith($name, '\\')) {
$extension = '';
}
foreach ($this->getAutoloadRules() as $prefix => $prefixPath) {
if (strpos($name, $prefix) === 0) {
return $prefixPath . str_replace('\\', '/', substr($name, strlen($prefix))) . $extension;
}
}
throw new \RuntimeException("Invalid class name: {$name}");
}

protected function getAutoloadRules(): array
{
return data_get(Composer::getJsonContent(), 'autoload.psr-4', []);
}
}
19 changes: 18 additions & 1 deletion src/utils/src/Composer.php
Expand Up @@ -21,6 +21,11 @@ class Composer
*/
private static $content;

/**
* @var Collection
*/
private static $json;

/**
* @var array
*/
Expand Down Expand Up @@ -71,10 +76,22 @@ public static function getLockContent(): Collection
return self::$content;
}

public static function getJsonContent(): Collection
{
if (! self::$json) {
$path = BASE_PATH . '/composer.json';
if (! is_readable($path)) {
throw new \RuntimeException('composer.json is not readable.');
}
self::$json = collect(json_decode(file_get_contents($path), true));
}
return self::$json;
}

public static function discoverLockFile(): string
{
$path = '';
if (file_exists(BASE_PATH . '/composer.lock') && is_readable(BASE_PATH . '/composer.lock')) {
if (is_readable(BASE_PATH . '/composer.lock')) {
$path = BASE_PATH . '/composer.lock';
}
return $path;
Expand Down
70 changes: 70 additions & 0 deletions src/utils/tests/CodeGen/ProjectTest.php
@@ -0,0 +1,70 @@
<?php

declare(strict_types=1);
/**
* This file is part of Hyperf.
*
* @link https://www.hyperf.io
* @document https://doc.hyperf.io
* @contact group@hyperf.io
* @license https://github.com/hyperf-cloud/hyperf/blob/master/LICENSE
*/

namespace HyperfTest\Utils\CodeGen;

use Hyperf\Utils\CodeGen\Project;
use PHPUnit\Framework\TestCase;

/**
* @internal
* @coversNothing
*/
class ProjectTest extends TestCase
{
public function testNamespaceFor()
{
$mock = $this->createProject();
$ns = $mock->namespace('app/Model');
$this->assertEquals('App\\Model\\', $ns);
}

public function testClassNameFor()
{
$mock = $this->createProject();
$ns = $mock->className('app/Model/User.php');
$this->assertEquals('App\\Model\\User', $ns);
}

public function testPathForClass()
{
$mock = $this->createProject();
$path = $mock->path('App\\Model\\Foo');
$this->assertEquals('app/Model/Foo.php', $path);
}

public function testPathForNamespace()
{
$mock = $this->createProject();
$path = $mock->path('App\\Model\\');
$this->assertEquals('app/Model/', $path);
}

public function testPathForNoExtension()
{
$mock = $this->createProject();
$path = $mock->path('App\\Model', '');
$this->assertEquals('app/Model', $path);
}

private function createProject(): Project
{
$mock = \Mockery::mock(Project::class)
->makePartial()
->shouldAllowMockingProtectedMethods();
$mock->shouldReceive('getAutoloadRules')
->andReturn([
'App\\' => 'app/',
]);
return $mock;
}
}