2017-10-19 80 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