Postanowiłem poznać nieco Laravela w wersji 4 i napotkałem na pewien problem, o którym niewiele znalazłem na sieci. Większość wątków odnosi się albo do własnych pakietów w /vendor
i używania composer.json
albo do kontrolerów w podkatalogach.
W głównym katalogu aplikacji app
stworzyłem sobie katalog providers
. W nim mam 2 pliki:
- ProviderInterface.php
- ProviderBaseClass.php
a poza tymi plikami chcę umieścić klasy w podkatalogach, które dziedziczą i implementują te dwa pliki. Niestety, nie jestem jeszcze zbyt biegły w przestrzeniach nazw, których do tej pory w PHP niewiele używałem i jeszcze nie do końca je czuję.
Testowałem wiele różnych wariantów, ale nie udało mi się poprawnie załadować klasy - dostaję albo błędy o braku klasy docelowej albo o braku klasy podstawowej, albo ścieżki do nich są błędne.
Jedna z wersji wygląda tak:
/app/providers/ProviderInterface.php:
<?php
namespace Providers; //czy to potrzebne?
interface ProviderInterface {
...
/app/providers/ProviderBaseClass.php:
<?php
namespace Providers; //czy to potrzebne?
class ProviderBaseClass implements ProviderInterface {
...
No i przykładowy plik w przykładowym podkatalogu:
/app/providers/pl/foo.php:
<?php
namespace Pl; //tu próbowałem i Providers/Pl i tak jak jest; próbowałem dodawać też "use Providers;"
class Foo extends \Providers\ProviderBaseClass implements \Providers\ProviderInterface { //tu próbowałem różnych opcji - bez \ na początku szuka w podkatalogu, czyli próbuje wczytać Pl/Providers/ProviderBaseClass
...
No i tworzenie klasy docelowej - tu też nie do końca czuję jaka wersja jest poprawna - testowałem między innymi:
new \Providers\Pl\Foo();
new Providers\Pl\Foo();
new \Pl\Foo();
new Pl\Foo();
new Foo();
Docelowo nazwę będę miał w stringu co jeszcze mocniej utrudnia. Będę miał np. $class = 'pl.foo';
Nie jestem pewien czy powinienem próbować tworzyć instancję w taki sposób, czy najpierw nie powinienem jakoś powiązać jej z IoC:
App::bind('Provider', function() {return new Pl/Foo();});
Jakby ktoś miał dobry i łopatologiczny opis przestrzeni nazw w PHP, to bym chętnie przyswoił. Tyle lat ich nie było w tym języku, że to taki mały przewrót dla mnie :)
[edited]
Byłbym zapomniał - w /app/start/global.php
dodałem:
ClassLoader::addDirectories(array(
...
app_path().'/providers',
));
Dodałem również w composer.json
:
"autoload": {
"psr-0": {
"Providers": "app/providers/"
},
Ale nie jestem pewien tak prawdę mówiąc ile rzeczy jest zbędnych. Za dużo magii jak dla gościa wychowanego na Assemblerze ;-)
[edit2]
Czyżbym znalazł odpowiedź?
Zamieniłem psr-0 na psr-4:
"autoload": {
"psr-4": {
"Providers\\": "app/providers/"
},
I jestem w stanie stworzyć instancję klasy:
$providerName = 'pl\\foo';
$provider = new $providerName();
Klasa ma taką definicję:
<?php
namespace Pl;
use Providers;
class Foo extends Providers\ProviderBaseClass implements Providers\ProviderInterface {
Czy takie podejście jest prawidłowe?