Laravel模型上的自定义查找方法应该是静态的吗?


Should a custom find method on a Laravel Model be static?

在以下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的服务容器进行自动依赖注入的控制器中,我们会对一个实例:$sections = $this->sections-> findByIdAndCourseOrFail(7,3);和我的IDE (PhpStorm)发出警告,如果Static

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

我不确定局部作用域是否应该这样使用。但是它在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);
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);
}

}

我个人会使这是一个静态方法,我不确定是否有一个"正确"的答案,虽然可以做到。我把它们分开的方法是如果我对一个模型的实例做了一些事情然后我把它变成一个普通的公共函数。如果我要对集合做一些事情,我会使用静态。例如:

$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);

希望你明白。