2014-07-12 10 views
6

Buduję numer CMS package for Laravel.Problemy związane z wykrywaniem i wymawianiem Laravel

Wszystkie moje models w tym pakiecie są powiązane i usuwane z kontenera IoC, dzięki czemu można je łatwo zastąpić w dowolnym pojedynczym wdrożeniu pakietu.

Dla nie polimorficznych związków, to zadziałało.

Na przykład, Page ma wiele PageModules, więc jego związek zmieniane od:

// \Angel\Core\Page 

public function modules() 
{ 
    return $this->hasMany('PageModule'); 
} 

do:

// \Angel\Core\Page 

public function modules() 
{ 
    return $this->hasMany(App::make('PageModule')); 
} 

Ale nie były w stanie dowiedzieć się, jak to zrobić to samo ze związkami polimorficznymi.

Na przykład menu zawierają MenuItems, a każda pozycja menu może być powiązana z jednym innym modelem, takim jak Page lub BlogPost.

Aby osiągnąć ten sposób laravel, dodałem następujące relacje z MenuItem:

// \Angel\Core\MenuItem 

public function linkable() 
{ 
    return $this->morphTo(); 
} 

i ten stosunek do LinkableModel, z których wszystkie modele, takie jak Page i blogpost rozszerzenia:

// \Angel\Core\LinkableModel 

public function menuItem() 
{ 
    return $this->morphOne(App::make('MenuItem'), 'linkable'); 
} 

Tabela menus_items (której używa MenuItems) ma następujące wiersze:

linkable_type  | linkable_id 
-------------------|-------------- 
\Angel\Core\Page | 11 
\Angel\Core\Page | 4 

Działa to znakomicie, ale potrzebuję, aby linkable_type wypowiedział "Stronę" zamiast "\ Angel \ Core \ Page" i aby został rozstrzygnięty na stronie "IoC", zamiast być zakodowany na sztywno na konkretnej klasie z nazwami.

Co Próbowałem:

Według this question, powinno być tak proste, jak definiujesz właściwości $morphClass do skorelowane() klasy, tak jak poniżej:

// \Angel\Core\Page 
protected $morphClass = 'Page'; 

Ale kiedy to stosuję i zmieniam tabelę menus_items tak, aby wyglądała następująco:

linkable_type | linkable_id 
---------------|-------------- 
Page   | 11 
Page   | 4 

... Po prostu otrzymuję komunikat o błędzie Class 'Page' not found. po wywołaniu metody connectka() w menuItem.

This is the exact line in Eloquent that throws the error.

Więc wbił wymowny i pomyślałem, że mogę być w stanie uciec z mniej więcej tak:

// \Angel\Core\MenuItem 

public function linkable() 
{ 
    return $this->morphTo(null, App::make($this->linkable_type)); 
} 

... to czuje się tak blisko, ale niestety: Eloquent wzywa skorelowane() zanim zostanie wypełnione pozostałe atrybuty/kolumny MenuItem, więc $ this-> linkable_type ma wartość null i dlatego nie rozwiąże niczego z IoC.

Dziękuję bardzo z góry za wszelkie wskazówki, jakie możesz mieć!

Odpowiedz

4
public function linkable() 
{ 
    return $this->morphTo(null, App::make($this->linkable_type)); 
} 

To nie zadziała w każdym przypadku, ponieważ morphTo() w Illuminate\Database\Eloquent\Model spodziewa

  1. nazwę relacji polimorficznych ('skorelowane')
  2. typ z obiekt do przekształcenia ("Strona", a nie instancja Page)
  3. id obiektu należy przekształcił

Jeśli nie są przewidziane, laravel jest wystarczająco inteligentny, aby je odgadnąć i następnie odpowiednio zwrócić Illuminate\Database\Eloquent\MorphTo obiekt.

Również, $this->linkable_type i $this->linkable_id nie powinny w tym kontekście być w rzeczywistości null.

Rzućmy okiem na odpowiedniej części funkcji morphTo():

$instance = new $class; 

return new MorphTo(
    $instance->newQuery(), $this, $id, $instance->getKeyName(), $type, $name 
); 

Uwaga: Jest to kod z wersji 4.2.6 kod związany powyżej wydaje się być od późniejsza wersja i jest nieco inna, a funkcja zwraca obiekt BelongsTo zamiast obiektu MorphTo.

Problem dotyczy w szczególności $instance = new $class; - lekcja jest po prostu rozwiązana i nie rozwiązana. Ale może po prostu chwycić tę część magii i poradzić sobie pytanie:

public function linkable() 
{ 
    $instance = App::make($this->linkable_type); 

    $id = 'linkable_id'; 
    $type = 'linkable_type'; 
    $name = 'linkable'; 

    return new MorphTo(
     $instance->newQuery(), $this, $id, $instance->getKeyName(), $type, $name 
    ); 
} 

Powinno to rzeczywiście działa (nie przetestowane go), ale nie jestem pewien o jakichkolwiek skutków ubocznych może powodować u niektórych krawędzi przypadki.

Albo można też po prostu zastąpić całą funkcję w swojej MenuItem -Model i po prostu ustawić odpowiednią część:

public function morphTo($name = null, $type = null, $id = null) 
{ 
    if (is_null($name)) 
    { 
     list(, $caller) = debug_backtrace(false); 

     $name = snake_case($caller['function']); 
    } 

    list($type, $id) = $this->getMorphs($name, $type, $id); 

    //eager loading 
    if (is_null($class = $this->$type)) 
    { 
     return new MorphTo(
      $this->newQuery(), $this, $id, null, $type, $name 
     ); 
    } 

    // normal lazy loading 
    else 
    { 
     // this is the changed part 
     $instance = \App::make($class); // new $class; 

     return new MorphTo(
      $instance->newQuery(), $this, $id, $instance->getKeyName(), $type, $name 
     ); 
    } 
} 

Uwaga: Działa to dobrze dla lazy-loading, ale nie pracuj dla szybkiego ładowania. An issue has been raised seeking a solution for eager-loading here.

Związek byłby wtedy jak zwykle:

public function linkable() 
{ 
    return $this->morphTo(); 
} 
+0

Jesteś geniuszem. Dziękuję bardzo za Twoją pomoc. Mówisz, że nie możemy podać nazwy dla null, ponieważ nie byłaby w stanie tego wydedukować, ale [to sprawiło, że myślałem, że to możliwe!] (Http://laravel.com/api/source-class- Illuminate.Database.Eloquent.Model.html # 523) – Leng

+0

Chociaż używam Laravel 4.1, który ma [ten morphTo] (https://github.com/laravel/framework/blob/2f1c6cd51dfd51d573977f07e34ba609cc0bf3ac/src/Illuminate/Database/Eloquent/ Model.php # L724). – Leng

+0

Szczury!Quasdunk, kiedy chciałem załadować tę relację, to już nie działa, ponieważ $ this-> linkable_type w tej sytuacji jest rzeczywiście zerowe. Przypuszczam, że przy pełnym obciążeniu, Eloquent wywołuje metody relacji przed wypełnieniem właściwości/kolumn. :(Będę ciągle szukał działającego rozwiązania – Leng

Powiązane problemy