2017-10-19 44 views
10

为了使这个更有趣,事情工作得很好,如果我运行composer dump-autoload -o,但我很好奇,为什么这会抛出一个错误,当我第一次运行composer update?我需要深究这一点。快速修复不会让我内心开心。ReflectionException抛出作曲家更新为一个文件存在

aligajani at Alis-MBP in ~/Projects/saveeo on master ✗                     [faaba41c] 4:53 
> composer update 
> php artisan clear-compiled 
Loading composer repositories with package information 
Updating dependencies (including require-dev) 
Nothing to install or update 
Package guzzle/guzzle is abandoned, you should avoid using it. Use guzzlehttp/guzzle instead. 
Generating autoload files 
> php artisan optimize 


    [ReflectionException]           
    Class Saveeo\Board\Observers\BoardEventListener does not exist 

BoardEventListener.php(置于Saveeo /板/观察员)

<?php 

namespace Saveeo\Board\Observers; 

use Saveeo\Services\HashIds\Contracts\HashIds as HashIdService; 

class BoardEventListener { 
    private $hashIdService; 

    public function __construct(HashIdService $hashIdService) { 
     $this->hashIdService = $hashIdService; 
    } 

    public function whenBoardIsCreated($event) { 
     $this->hashIdService->syncHashIdValueOnModelChanges($event, 'board'); 
    } 

    public function whenBoardIsUpdated($event) { 
     $this->hashIdService->syncHashIdValueOnModelChanges($event, 'board'); 
    } 

    public function subscribe($events) { 
     $events->listen(
      'Saveeo\Board\Observers\Events\BoardHasBeenCreated', 
      'Saveeo\Board\Observers\[email protected]' 
     ); 

     $events->listen(
      'Saveeo\Board\Observers\Events\BoardHasBeenUpdated', 
      'Saveeo\Board\Observers\[email protected]' 
     ); 

    } 
} 

EventServiceProvider.php(置于Saveeo /供应商)

<?php 

namespace Saveeo\Providers; 

use Illuminate\Contracts\Events\Dispatcher as DispatcherContract; 
use Illuminate\Foundation\Support\Providers\EventServiceProvider as ServiceProvider; 

class EventServiceProvider extends ServiceProvider 
{ 
    /** 
    * The event listener mappings for the application. 
    * 
    * @var array 
    */ 
    protected $listen = [ 
     // 
    ]; 

    /** 
    * The subscriber classes to register. 
    * 
    * @var array 
    */ 
    protected $subscribe = [ 
     'Saveeo\Board\Observers\BoardEventListener', 
    ]; 

    /** 
    * Register any other events for your application. 
    * 
    * @param \Illuminate\Contracts\Events\Dispatcher $events 
    * @return void 
    */ 
    public function boot(DispatcherContract $events) { 
     parent::boot($events); 

     // 
    } 
} 

这里是文件夹结构。在这里看不到任何错误?

https://imgur.com/BI44Lq6

Composer.json

{ 
    "name": "laravel/laravel", 
    "description": "The Laravel Framework.", 
    "keywords": [ 
     "framework", 
     "laravel" 
    ], 
    "license": "MIT", 
    "type": "project", 
    "require": { 
     "php": ">=5.5.9", 
     "laravel/framework": "5.2.*", 
     "firebase/php-jwt": "~2.0", 
     "guzzlehttp/guzzle": "5.*", 
     "guzzlehttp/oauth-subscriber": "0.2.0", 
     "laravel/socialite": "2.*", 
     "league/flysystem-aws-s3-v3": "~1.0", 
     "aws/aws-sdk-php": "3.*", 
     "bugsnag/bugsnag-laravel": "1.*", 
     "vinkla/hashids": "^2.3" 
    }, 
    "require-dev": { 
     "fzaninotto/faker": "~1.4", 
     "mockery/mockery": "0.9.*", 
     "phpunit/phpunit": "~4.0", 
     "phpspec/phpspec": "~2.1", 
     "tymon/jwt-auth": "0.5.*", 
     "symfony/dom-crawler": "~3.0", 
     "symfony/css-selector": "~3.0" 
    }, 
    "autoload": { 
     "classmap": [ 
      "database" 
     ], 
     "psr-4": { 
      "Saveeo\\": "app/" 
     } 
    }, 
    "autoload-dev": { 
     "classmap": [ 
      "tests/TestCase.php" 
     ] 
    }, 
    "scripts": { 
     "post-install-cmd": [ 
     "php artisan clear-compiled", 
     "php artisan optimize" 
    ], 
    "pre-update-cmd": [ 
     "php artisan clear-compiled" 
    ], 
    "post-update-cmd": [ 
     "php artisan optimize" 
    ], 
    "post-root-package-install": [ 
     "php -r \"copy('.env.example', '.env');\"" 
    ], 
    "post-create-project-cmd": [ 
     "php artisan key:generate" 
    ] 
    }, 
    "config": { 
     "preferred-install": "dist" 
    } 
} 
+0

@Leith请参阅我的composer.json –

回答

7

看起来我们在作曲家班改变了自动加载的命名空间(手动,或通过使用artisan app:name)在应用程序/目录从App(默认值)Saveeo。JSON

"autoload": { 
    "psr-4": { 
     "Saveeo\\": "app/" 
    } 
}, 

这是完全很好,当我们了解了影响的事情。我们可以看到在这个问题描述时,我们先来看看该项目的文件夹结构导致异常(括号中的命名空间),该文件的问题:

app     (Saveeo) 
├── Saveeo    (Saveeo\Saveeo) 
│   ├── Board   (Saveeo\Saveeo\Board) 
│ │   ├── Observers (Saveeo\Saveeo\Board\Observers) 
│ │ │   ├── BoardEventListener 
└── ... 

对于PSR-4,命名空间的兼容性对于BoardEventListener应该是Saveeo\Saveeo\Board\Observers,因为它存在于Saveeo/目录下,嵌套在app/下。 PSR-4 autoloading实现根据解析类文件的文件名和路径, 不是命名空间 中的文件。 [作曲家确实只要顶级命名空间匹配,就从类文件读取命名空间以创建优化的类映射。见更新]

如果我们不希望改变应用程序的目录结构,我们也不想在命名空间中使用两个Saveeo S,我们可以配置作曲到两个目录合并成当它自动加载类时:

"autoload": { 
    "psr-4": { 
     "Saveeo\\": [ "app/", "app/Saveeo/" ] 
    } 
}, 

...并记住要composer dump-autoload

它的工作原理,但我不建议这在实践中。它偏离了PSR-4标准,使得应用程序易受名称空间冲突的影响,并且可能会让其他从事项目工作的人感到困惑。我建议你将Saveeo命名空间和目录弄平,或者为嵌套目录中的类选择一个不同的命名空间。

...things work just fine if I run composer dump-autoload -o but I am curious why would this throw an error when I run composer update ...?

生成自动加载缓存文件时,Composer实际上并不执行您的代码。但是,在大多数Laravel应用程序(直到5.5),之后运行composer updateartisan optimize命令会引导应用程序执行其操作,因此问题代码将执行并且我们会看到异常。

更新:

If using Saveeo\Board\etc was wrong versus doing Saveeo\Saveeo\Board\etc then other files around the entire application wouldn't work, but they do.

我们可以技术上使用不项目的目录结构相匹配的非PSR-4命名空间,当我们产生优化自动加载,正如我们所准备的生产应用:

composer dump-autoload --optimize 

这是可行的,因为Composer会扫描每个类文件的命名空间s创建一个静态 classmap。当我们没有指定--optimize时,Composer依靠动态自动加载,它将文件路径与命名空间相匹配,因此非标准名称空间或目录结构无法解析。

虽然它不符合PSR-4,但大部分项目的命名空间仍然有效,因为我们使用-o选项为dump-autoload手动转储优化的自动加载器。但是,我们看到错误消息,因为在运行更新之前,composer update删除缓存的类图,因此,在运行artisan optimize命令时,类映射不再包含我们转储的类。

我们可以通过 composer.json设置optimize-autoloader配置指令配置Composer来always optimize the autoloader

"config": { 
    "optimize-autoloader": true 
} 

...这应该可以解决installupdate命令为这个项目。获取非标准名称空间来解决这个问题有点麻烦。有了这种方法,请记住,只要我们在开发中添加不遵循PSR-4的新文件,就需要转储自动加载器。

+0

这当然假设应用程序名称空间实际上是通过使用'php artisan app:name Saveeo'命令从'App'改变的,而不是简单地在'composer.json'中改变,这将毫无用处它。 – Leith

+0

@Leith根据问题中的服务提供者,我假设Ali使用这个命令或手动更改每个文件中的命名空间。但你是对的 - 我们不能认为这是真的。 –

+1

我使用'php工匠应用程序:名称Saveeo'。正确。说实话,我没有其他地方使用'Saveeo \ Saveeo',那么为什么我会在特定的文件中使用它。如果使用'Saveeo \ Board \ etc'与执行'Saveeo \ Saveeo \ Board \ etc'是错误的,那么整个应用程序中的其他文件将不起作用,但它们确实如此。不过,我会尝试这个并报告回来。 –

3

我相信,如果你只需要改变你的命名空间:的

App\Saveeo\Board\Observers代替Saveeo\Board\Observers

所有的问题应该得到解决。请让我知道,如果您有创建这个新名称空间的原因,而不是从基本App名称空间分支出来。

+2

为什么要使用'App'命名空间。 'Saveoo'就是这样。 –

+0

您的Saveeo目录位于您的App目录下。那么为什么要在现有的名称空间中创建第二个名称空间?你看到这样做的好处吗?你有没有至少试过我建议看看你的问题是否会以这种方式解决? –

+0

当你在'vendor'目录下有一个包时,那种名称空间是正确的,但是'app'文件夹中的代码更好地使用'App'名称空间,因为它是主名称空间。这是组织代码的一个很好的理由 – Lloople

6

这似乎与Composer PSR自动加载有关。默认情况下Laravel将包括

"autoload": { 
    "psr-4": { 
     "App\\": "app/" 
    } 
} 

意思是“App命名空间的根是在app文件夹,并从那里匹配命名空间的文件夹结构”。

您的Saveeo名称空间尚未注册(它不在App层次结构中),因此Composer不知道它的位置。

如果添加另一条线路的composer.json(然后dump-autoload)它应该工作

"autoload": { 
    "psr-4": { 
     "App\\": "app/", 
     "Saveeo\\": "app/Saveeo" 
    } 
} 

或者,你可以,因为对方的回答中指出,只需将整个Saveeo命名空间内App(所以它的例子是App\Saveeo\Board\Observers\Events\BoardHasBeenCreated)。然而,您的Saveeo名称空间似乎是一个独立的模块,将它作为单独的名称空间而不是重命名其所有文件中的名称空间可能更合理。

+0

请参阅我的composer.json –

+0

@AliGajani这是正确的答案,_unless_您已经使用'artisan'将root namspace从'App'重命名为'Saveeo',在这种情况下,您的'app/Saveeo'文件夹**和**你的'app /'文件夹将在'Saveeo'命名空间中。或者,如果主命名空间没有改变,那么你可以改变你的所有命名空间为[这个答案](https://stackoverflow.com/a/46889828/2053165)。 – Leith

+0

@AliGajani如果您将'Saveeo'命名空间与'app'文件夹相匹配,则不需要'Saveeo'文件夹。也许'Saveeo \ Board \ Observers \ Events \ BoardHasBeenCreated'类可以在'app/Board/Observers/Events/BoardHasBeenCreated.php'文件中。 – alepeino