首页  >  问答  >  正文

使用不同参数的 Laravel PHP 重写方法

如果之前已经多次询问过这个问题,并且这在 Laravel/PHP 中根本不可行,那么我们深表歉意。

在我的 Laravel 应用程序中,我有一个 PostController,它使用 Laravel 丰富的命名约定。我还有一个 CommentController,它主要以各种方式复制 PostController,因此我决定 CommentController 应该扩展 PostController.

到目前为止唯一的区别是 store() 方法需要接受不同的 FormRequest 对象,因为它们具有不同的验证规则。因此,我重写了 store() 方法以期望 CommentFormRequest 而不是 PostFormRequest (两者都扩展了 FormRequest) .

这会引发一个错误,即重写方法参数需要与基本方法匹配。

这是预期的吗?对于我想做的事情有一个合理的解决方案吗?

从此处编辑

我刚刚开始设计这个项目,用户可以在其中创建帖子、问题、投票、广告等,并且可以对其中任何内容发表评论。

所有这些都是Post类型。有些与其他模型有关系,例如Poll 可能与 PredefinedAnswer 模型有关系,而通用 Post 可能没有关系。

有些可能需要不同的验证逻辑,例如用户可以决定是否允许对通用 Post 发表评论,但可能永远不允许对 Advert 发表评论。

在我的数据库中,我认为这些都可以存储在 post 表中,但具有不同的 postable_type

在我的控制器中,我认为这些不同类型之间的大多数 CRUD 逻辑是相同的。在某些情况下,可能存在差异,可能需要重写方法。

因此,在我的 PostController 中,我目前有一个非常简单的 store() 方法:

class PostController extends Controller
{

    protected $postableType;


    public function __construct()
    {
        $this->postableType = PostType::GENERIC;
    }

    public function store(PostStoreRequest $request): RedirectResponse
    {
        $validated = $request->validated();

        $post = new Post();
        $post->message = $validated['message'];
        $post->user_id = $request->user()->id;

        $post->postable_type = $this->postableType;

        $post->save();

        return Redirect::route('feed');
    }
}

假设我的 AdvertController 具有相同的逻辑,但具有我所想的不同的验证规则:

class AdvertController extends PostController
{

    protected $postableType;

    public function __construct()
    {
        $this->postableType = PostType::ADVERT;
    }

    public function store(AdvertStoreRequest $request): RedirectResponse
    {
        $validated = $request->validated();

        $advert= new Advert();
        $advert->message = $validated['message'];
        $advert->user_id = $request->user()->id;

        $advert->postable_type = $this->postableType;
        $advert->save();

        return Redirect::route('feed');
    }

P粉863295057P粉863295057300 天前449

全部回复(1)我来回复

  • P粉807471604

    P粉8074716042024-01-17 16:43:49

    与其暗示具体的实现,不如暗示接口,你会得到更多的收益,例如:

    interface StoreRequestInterface {
      public function validated(): RedirectResponse;
      public function user();
      // etc
    }
    
    class PostStoreRequest implements StoreRequestInterface {/* ... */}
    class AdvertStoreRequest  implements StoreRequestInterface {/* ... */}
    
    abstract class Controller {
        protected $postableType;
    
        public function store(StoreRequestInterface $request): RedirectResponse
        {
            // ...
        }
    }
    
    class PostController extends Controller
    {
        public function __construct()
        {
            $this->postableType = PostType::GENERIC;
        }
    }
    
    class AdvertController extends PostController
    {
        public function __construct()
        {
            $this->postableType = PostType::ADVERT;
        }
    }
    

    这样你:

    • 不必使用略有不同的参数提示来重新定义相同的方法体。
    • 在需要一些特殊处理的情况下可以调用 parent::store($request),例如:类型/健全性检查,但该方法的其余部分仍然相同。
    • 可以避免定义“上帝”类的陷阱,大量应用程序类必须追踪其血统。您可以通过简单地实现预期的接口来定义独立的直接替换。

    您可以进一步连接此处引用的其他类[例如:ControllerInterfaceRedirectInterface等],并进一步简化您的代码。

    回复
    0
  • 取消回复