【问题标题】:Should a custom find method on a Laravel Model be static?Laravel 模型上的自定义查找方法应该是静态的吗?
【发布时间】:2017-03-19 15:54:56
【问题描述】:

在下面的 Laravel 5 模型中,findByIdAndCourseOrFail 方法应该是静态的吗?

class Section extends Model {

    //should this method be static?
    public function findByIdAndCourseOrFail($id, $courseId)
    {

        $result = $this->where('id', $id)->where('course_id', $courseId)->first();

        if (!is_null($result))
        {
            return $result;
        }

        throw (new ModelNotFoundException())->setModel(Section::class);

    }


    }

使用控制器:

class SectionsController extends Controller {

protected $sections;

public function __construct(Section $section)
{

    $this->sections = $section;

}

public function foo($id, $courseId)  //illustration only
{
     $section = $this->sections->findOrFail($id);   

     $section = $this->sections->findByIdAndCourseOrFail($id, $courseId);  
     //would need to be non-static

     $section = Section::findByIdAndCourseOrFail($id, $courseId); 
     //weird when compared with find above
}

一方面,我们没有作用于 Section 实例 [参见注释]。另一方面,在通过Laravel's service container 进行自动依赖注入的控制器中,我们将作用于一个实例:$sections = $this->sections-> findByIdAndCourseOrFail(7,3);,如果Static,我的 IDE (PhpStorm) 会发出声音。

[注意]:此评论可能是对 Laravel 模型如何工作的误解。对我来说,我希望 find()findOrFail() 是类方法,因此是静态的,而不是 find 方法将返回的实例。

【问题讨论】:

  • 好吧,$this 在静态方法中不可用。
  • 当然,如果方法改成static,$this->会改成self::
  • 但是 where()first() 也需要更改,如果在其中定义了这些方法,则可能需要更改整个 Model
  • 为什么 where() 和 first(0 需要更改?这些方法在 Laravel Eloquent 模型类中定义(或可访问)。

标签: php laravel methods eloquent


【解决方案1】:
class Section extends Model {


public static function findByIdAndCourseOrFail($id, $courseId)
{

    $result = self::where('id', $id)->where('course_id', $courseId)->first();

    if (!is_null($result))
    {
        return $result;
    }

    throw (new ModelNotFoundException())->setModel(Section::class);

}


}

【讨论】:

  • 问题不在于如何使方法静态化。相反,它是否应该是静态的。
  • 好吧,在这种情况下......它应该是静态的,这对我来说更有意义。您静态调用此方法,因此它会为您返回一个模型。
  • 如果你已经有了模型,或者它是实例,在它上面调用 find 是没有意义的
  • 虽然通过 Laravel 的服务容器进行自动依赖注入,但情况并非如此。控制器有一个使用 PHP 反射机制自动注入的类的实例。在这些情况下,您确实可以致电find
  • 这真的很难,我认为没有一个答案,所以我会凭直觉说它应该是静态的。
【解决方案2】:

就我个人而言,我会将其设为静态方法,但我不确定是否有“正确”的答案,尽管两者都可以。我在脑海中将它们分开的方式是,如果我对模型的实例做某事,那么我将其设为正常的公共函数。如果我对 Collection 做某事,我会使用静态。例如:

$person = new Person();
$person->setAdmin(true);
$person->save();

// OR

$admins = Person::getAdmins();

在第一个示例中,我们有一个 Person 的特定实例,并且我们正在对其进行操作,所有代码都只是在操作该特定实例。在第二个示例中,我们对Person 的整个集合进行操作,并且我们希望返回一个对象集合。

在您的情况下,您必须启动 Section 的实例才能使用您的非静态公共方法,如下所示:

$section = new Section();
$foundSection = $section->findByIdAndCourseOrFail(7,3);

所以$section 成为一个从未真正使用过的临时变量。另一方面,如果您将其设为静态,则无需执行此操作即可调用它。

$section = Section::findByIdAndCourseOrFail(7,3);

希望这是有道理的。

【讨论】:

  • 感谢您的回复。关于:“在您的情况下,您必须启动 Section 的实例才能使用您的非静态公共方法,就像这样”。事实上,情况并非如此。在控制器中,我使用反射,实例自动注入到构造函数中。 public function __construct(Section $sections){ $this->sections = $sections} 在这种情况下,静态的意义不大,尽管通常我会按照您的逻辑工作,因此提出了问题!
  • 无论如何,我认为我不会为这种情况破例。如果您需要在不同的时间在其他地方使用该功能怎么办?我会坚持你的标准。
  • 我不认为这是一个例外。服务容器的自动注入被广泛使用,find() 方法本身不是静态调用的,将其设为静态会抵消注入的好处,因为我将使用实例而不是我的 @987654331 进行 find() 调用@ 调用看起来很奇怪!
  • 我想,我正在寻找一个更客观的答案。 find() 方法本身是 static 还是不是?很难说,因为它隐藏在 Eloquent\Builder 类中,但它看起来是非静态的。我认为重构以使用存储库会使这一点没有实际意义,但这似乎有点过头了。
  • 我已经编辑了上面的问题以显示控制器以更好地说明困境。
【解决方案3】:

我不确定local scopes 是否打算这样使用。但它适用于 laravel 5.2:

public function scopeFindByIdAndCourseOrFail($query, $id, $courseId)
{
    $result = $query->where('id', $id)->where('course_id', $courseId)->first();

    if (!is_null($result))
    {
        return $result;
    }

    throw (new ModelNotFoundException())->setModel(Section::class);
}

在控制器中你可以同时使用它:

$section = Section::findByIdAndCourseOrFail($id, $courseId);

或者

$model = new Section();
$section = $model->findByIdAndCourseOrFail($id, $courseId);

【讨论】:

  • 这确实是正确的做法。深入查看源代码,没有一个模型方法实际上是静态的。 model::find() 是语法糖,因此使用保留相同质量的范围是正确的方法。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-03-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-06-23
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多