2016-07-23 31 views
3

Laravel路由中的常見設置是使用嵌套資源和路由模型綁定。這允許偉大的邏輯URL來表示模型在數據庫中相互之間的實際關係。這可能是/ library/section/book /的一個例子。該書由該部分擁有,該部分由圖書館擁有。但是當使用路由模型綁定時,這些資源的id會變成沒有任何其他知識的模型。/1/7/234將返回這些資源的模型,但不能保證它們有適當的關聯。書籍234可能不屬於第7部分,第7部分可能不屬於圖書館1。我經常在每個控制器的頂部有一個方法來處理檢查我所稱的關係測試。這個功能可以在Book控制器中找到。從嵌套資源檢查模型關係

private function relationshipCheck($library, $section, $book) 
{ 
    if(library->id == $section->library_id) { 
     if($book != false) { 
      if($section->id == $book->section_id) { 
       return true; 
      } else { 
       return response()->json(["code" => 401], 401); 
      } 
     } else { 
      return true; 
     } 
    } else { 
     return response()->json(["code" => 401, 401); 
    } 
} 

什麼是正確的方式來處理使用這些代表關係的路線?有沒有更自動化的方式來做到這一點?當關系都是一對多關係時,是否有理由忽視所有內容,而不是最後一個資源?

回答

0

我遇到過需要做這個之前。這就是我已經做到了:

在我RouteServiceProvider.php文件我有以下方法:

private function addSlugBindingWithDependency(Router $router, $binding, $className, $dependency, $dependencyClassName, $dependencyField) 
{ 
    $router->bind($binding, function($slug, $route) use($className, $dependency, $dependencyClassName, $dependencyField) { 
     if (!is_string($slug)) { 
      throw new NotFoundHttpException; 
     } 

     $params = $route->parameters(); 
     if (!$params || !isset($params[$dependency]) || get_class($params[$dependency]) != $dependencyClassName) { 
      throw new NotFoundHttpException; 
     } 

     $dependencyInstance = $params[$dependency]; 

     $item = $className::where('slug', $slug)->where($dependencyField, $dependencyInstance->id)->first(); 
     if (!$item) { 
      throw new NotFoundHttpException; 
     } 

     return $item; 
    }); 
} 

這是一個功能,可以幫助我建立一個路由/模型蛞蝓結合,其中該slug取決於URL /路徑的另一部分。它通過查看已經綁定的路線部分並抓取先前綁定的模型實例並使用它來檢查兩者是否鏈接在一起。

我也有另一個更基本的幫助函數,addSlugBinding,我用它來將一個slu bind綁定到一個對象上。

你可以使用它在RouteServiceProvider類的這樣的引導方法:

public function boot(Router $router) 
{ 
    parent::boot($router); 

    $this->addSlugBinding($router, 'librarySlug', 'App\Library'); 
    $this->addSlugBindingWithDependency($router, 'sectionSlug', 'App\Section', 'librarySlug', 'App\Library', 'library_id'); 
    $this->addSlugBindingWithDependency($router, 'bookSlug', 'App\Book', 'sectionSlug', 'App\Section', 'section_id'); 
} 

然後在我的路線文件,我可能有以下幾點:

Route::get('{librarySlug}/{sectionSlug}/{bookSlug}', function($librarySlug, $sectionSlug, $bookSlug) { 

}); 

注:我當我通過slug而不是ID來嵌套URL時,我已經做到了這一點,但它可以很容易地適用於使用ID。

0

...當使用路由模型綁定時,這些資源的id會變成模型,彼此之間沒有任何知識。

我剛剛開始處理這個問題,這裏是我決定做的方法。

  • 使用戶更容易檢查模型的關係
    • Laravel 5.3有一個方法,以確定是否兩款車型具有相同的ID,並屬於同一個表。 is()
    • 我提交了一個pull request that would add relationship tools。您可以看到我在項目中使用的Illuminate\Database\Eloquent\Model的更改。
  • 使用模型綁定爲嵌套路線創建中間件。

中間件

<?php 

namespace App\Http\Middleware; 

use Closure; 
use Illuminate\Database\Eloquent\Model; 
use Illuminate\Http\Exception\HttpResponseException; 

/** 
* Class EntityChain 
* 
* Determine if bound models for the route are related to 
* each other in the order they are nested. 
* 
* @package App\Http\Middleware 
*/ 
class EntityChain 
{ 
    /** 
    * Handle an incoming request. 
    * 
    * @param \Illuminate\Http\Request $request 
    * @param \Closure $next 
    * @return mixed 
    */ 
    public function handle($request, Closure $next) 
    { 
     // Array of the bound models for the route. 
     $parameters = array_filter($request->route()->parameters(), 
      function ($v) { 
       if ($v instanceof Model) return true; 
       return false; 
      }); 

     // When there are two or more bound models. 
     if (count($parameters) > 1) { 

      // The first model is the parent. 
      $parent = array_shift($parameters); 

      while (count($parameters) > 0) { 

       // Assume the models are not related. 
       $pass = false; 

       // Set the child model. 
       $child = array_shift($parameters); 

       // Check if the parent model is related to the child. 
       if ($parent->is_related($child)) { 
        $pass = true; 
       } 

       $parent = $child; 


       // Fail on no relation. 
       if (!$pass) { 
        throw new HttpResponseException(response()->json('Invalid resource relation chain given.', 406)); 
       } 
      } 
     } 

     return $next($request); 
    } 
}