Laravel:从一个控制器

时间:2015-12-02 22:57:04

标签: laravel url resources nested

案例

我有两个对象,UserItem(现在可能会更晚),我可以使用以下网址模式附加文件:

/users/:user_id/attachments/:id
/items/:item_id/attachments/:id

为了保持DRY,我想只使用一个独特的控制器(AttachmentsController)来处理每一个案例。

问题

使用唯一控制器,嵌套资源可以是UserItem(或我想要附加到其上的任何其他对象)。有没有办法,使用RouteRequest从这个控制器动态检索这些资源(用户,项目......等......)?

理想环境

对我来说理想的用例是能够检索诸如/users/:user_id/attachments/:id之类的url模式,这样我就可以动态查找要使用的对象(参见下面的Rails解决方案)。当然,如果存在更好的解决方法,我就在。

我还在考虑做一些像动态检索对象的mixin:

trait ResourceFinder
{
    public function behaveableFrom(Request $request, $id)
    {
        $patternWords = explode('/', $request->path());
        $classname = ucfirst(str_singular($words[0]));
        return $classname::findOrFail($id);
    }
}

等效Rails解决方案

有关信息,我使用以下代码段在Ruby on Rails上完全相同:

module Behaveable
  module ResourceFinder
    def behaveable
      klass, param = behaveable_class
      klass.find(params[param.to_sym]) if klass
    end
  end

  def behaveable_class
    params.each do |name, _value|
      if name =~ /(.+)_id$/
        model = name.match(%r{([^\/.]*)_id$})
        return model[1].classify.constantize, name
      end
    end
    nil
  end
end

建议?

2 个答案:

答案 0 :(得分:0)

您可以使用路线资源控制器。

Route::resource('user.attachments', 'AttachmentsController');

http://laravel.com/docs/5.1/controllers#restful-nested-resources 但是你想要使用一个控制器,所以你有这样的选择: 1)为restful controller中的每个方法创建一些检查器,以检查它是Item还是User 2)使用所需方法创建一些AttachmentsBaseController,然后创建 另外2个控制器User \ ItemController将扩展基础控制器。通过这种方式,您可以定义基本工作流,如果某些内容发生变化取决于User \ Item,您可以在相关控制器中重新定义所需的方法。

答案 1 :(得分:0)

我终于使用mixin找到了一个非常干净的解决方案,正如我在原帖上所述。

<强> routes.php文件

foreach (['users', 'menus'] as $resource) {
    Route::resource("$resource.attachments", 'AttachmentsController', ['except' => ['create', 'edit']]);
}

应用\ HTTP \控制器\性状\ BehaveableFinder.php

<?php

namespace App\Http\Controllers\Traits;

use Illuminate\Http\Request;

trait BehaveableFinder
{
    /**
     * Get the behaveable object.
     *
     * @param  Request  $request
     * @param  int  $id
     * @return \Illuminate\Database\Eloquent\Model
     */
    public function behaveableFrom(Request $request, $behaveableId)
    {
        $context = explode('/', $request->path())[0];
        $class = 'App\\Models\\' . ucfirst(str_singular($context));
        return $class::findOrFail($behaveableId);
    }
}

应用\ HTTP \控制器\ AttachmentsController.php

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\Http\Requests;
use App\Http\Controllers\Controller;
use App\Http\Controllers\Traits\BehaveableFinder;

class AttachmentsController extends Controller
{
    use BehaveableFinder;

    /**
     * Get attachable's medias.
     *
     * GET http://domain.com/:attachable/:attachableId/attachments
     *
     * @param  Request  $request
     * @param  int      $attachableId
     * @return Response
     */
    public function index(Request $request, $attachableId)
    {
        $attachable = $this->behaveableFrom($request, $attachableId);
        return response()->json($attachable->medias, 200);
    }

    // ...rest of crud methods works the same way
}

这里的优点是,此mixin可用于任何其他多态上下文,例如注释(可注释对象)。这种方法的局限性在于它只能在深度为2的嵌套级别上工作。但是,在REST设计中避免过多的嵌套级别通常是一种很好的做法。

我认为总有改进的余地,如果您有任何改进方案,我很乐意看到其他方法,欢迎提出建议。