为什么在 Laravel 构造函数中访问 Facade 会失败?
Why does accessing a Facade in a Laravel constructor fail?
我目前正在尝试在 Laravel 中实现存储库模式。
我有一个接口声明了成为有效存储库所需的最少方法。
<?php
namespace App\Repositories;
interface RepositoryInterface
{
public function all();
public function create($entity);
public function update($entity);
public function find($id);
public function delete($entity);
}
我有一个抽象 class 表示我存储库中的接口方法,如下所示:
namespace App\Repositories;
use DB;
abstract class DbRepository
{
public function all()
{
return DB::table($this->tableName)->get();
}
public function create($user)
{
return $user->save();
}
public function update($user)
{
return $user->update();
}
public function find($id)
{
return DB::table($this->tableName)->where('id', $id)->first();
}
public function delete($user)
{
return $user->delete();
}
}
还有一个 UserRepository
实现接口并从抽象 class 继承,如下所示:
namespace App\Repositories;
use App\Models\User;
class UserRepository extends DbRepository implements RepositoryInterface
{
public $tableName;
public function __construct($tableName = 'users')
{
$this->tableName = $tableName;
}
/**
* Override the parent find method, as we want to return an instance of App\Models\User instead of stdClass
* @param $id
* @return mixed
*/
public function find($id)
{
return User::where('id', $id)->first();
}
}
以上一切正常,我的单元测试通过了。但是,我决定将当前数据库 table 作为存储库抽象实现的 属性 保存会很好,因此我将 class 重构为如下所示:
abstract class DbRepository implements RepositoryInterface
{
private $table;
public function __construct()
{
$this->table = DB::table($this->tableName);
}
public function all()
{
return $this->table->get();
}
# etc, etc...
然后确保从存储库的构造函数调用了抽象 class' 构造函数:
public function __construct($tableName = 'users')
{
$this->tableName = $tableName;
parent::__construct();
}
执行此操作后,我收到以下错误,我无法修复 Error: Class 'DB' not found
当 运行 PhpUnit.
我知道这个错误与我尝试重构事物的方式有关。我认为这与尝试在抽象 class 的构造函数中访问 DB
Facade 有关(因为在同一 class 中的其他方法中访问 DB
很好)。任何解释将不胜感激 - 我很好奇为什么它不起作用。
我已经将它还原为原始代码(这很好,真的)并且测试再次通过!
哦,如果你想查看我的测试,它们是:
namespace Tests\Repositories;
use TestCase;
use App\Repositories\UserRepository;
use App\Models\User;
use Illuminate\Foundation\Testing\DatabaseMigrations;
class UserRepositoryTest extends TestCase
{
use DatabaseMigrations;
private $repository;
public function __construct()
{
$this->repository = new UserRepository();
}
public function newUser()
{
return new User([
'name' => 'Joe',
'username' => 'joe',
'password' => bcrypt('password'),
'email' => 'joe@apple.com'
]);
}
public function test_all_method_returns_all_users()
{
$this->assertNotNull($this->repository->all());
}
public function test_create_user()
{
$this->assertTrue($this->repository->create($this->newUser()));
}
public function test_update_user()
{
// Arrange
$user = $this->newUser();
// Act
$this->repository->create($user);
$user->name = 'Jack';
// Assert
$this->assertTrue((integer)$this->repository->update($user) === 1);
}
public function test_delete_user()
{
// Arrange
$user = $this->newUser();
// Act
$this->repository->create($user);
// Assert
$this->assertTrue((integer)$this->repository->delete($user) === 1);
}
public function test_find_user()
{
// Arrange
$user = $this->newUser();
// Act
$this->repository->create($user);
// Assert
$this->assertInstanceOf(User::class, $this->repository->find($user->id));
}
}
不要在测试用例中覆盖 __construct()
。
测试用例是在早期实例化的,并且还依赖于您不调用的PHPUnit_Framework_TestCase
constructor。 DB
的自动加载器此时可能尚未初始化。
改用 setUp()
,它在每次测试之前都会被调用,并且是为这种初始化而设计的:
protected function setUp()
{
$this->repository = new UserRepository();
}
我目前正在尝试在 Laravel 中实现存储库模式。
我有一个接口声明了成为有效存储库所需的最少方法。
<?php
namespace App\Repositories;
interface RepositoryInterface
{
public function all();
public function create($entity);
public function update($entity);
public function find($id);
public function delete($entity);
}
我有一个抽象 class 表示我存储库中的接口方法,如下所示:
namespace App\Repositories;
use DB;
abstract class DbRepository
{
public function all()
{
return DB::table($this->tableName)->get();
}
public function create($user)
{
return $user->save();
}
public function update($user)
{
return $user->update();
}
public function find($id)
{
return DB::table($this->tableName)->where('id', $id)->first();
}
public function delete($user)
{
return $user->delete();
}
}
还有一个 UserRepository
实现接口并从抽象 class 继承,如下所示:
namespace App\Repositories;
use App\Models\User;
class UserRepository extends DbRepository implements RepositoryInterface
{
public $tableName;
public function __construct($tableName = 'users')
{
$this->tableName = $tableName;
}
/**
* Override the parent find method, as we want to return an instance of App\Models\User instead of stdClass
* @param $id
* @return mixed
*/
public function find($id)
{
return User::where('id', $id)->first();
}
}
以上一切正常,我的单元测试通过了。但是,我决定将当前数据库 table 作为存储库抽象实现的 属性 保存会很好,因此我将 class 重构为如下所示:
abstract class DbRepository implements RepositoryInterface
{
private $table;
public function __construct()
{
$this->table = DB::table($this->tableName);
}
public function all()
{
return $this->table->get();
}
# etc, etc...
然后确保从存储库的构造函数调用了抽象 class' 构造函数:
public function __construct($tableName = 'users')
{
$this->tableName = $tableName;
parent::__construct();
}
执行此操作后,我收到以下错误,我无法修复 Error: Class 'DB' not found
当 运行 PhpUnit.
我知道这个错误与我尝试重构事物的方式有关。我认为这与尝试在抽象 class 的构造函数中访问 DB
Facade 有关(因为在同一 class 中的其他方法中访问 DB
很好)。任何解释将不胜感激 - 我很好奇为什么它不起作用。
我已经将它还原为原始代码(这很好,真的)并且测试再次通过!
哦,如果你想查看我的测试,它们是:
namespace Tests\Repositories;
use TestCase;
use App\Repositories\UserRepository;
use App\Models\User;
use Illuminate\Foundation\Testing\DatabaseMigrations;
class UserRepositoryTest extends TestCase
{
use DatabaseMigrations;
private $repository;
public function __construct()
{
$this->repository = new UserRepository();
}
public function newUser()
{
return new User([
'name' => 'Joe',
'username' => 'joe',
'password' => bcrypt('password'),
'email' => 'joe@apple.com'
]);
}
public function test_all_method_returns_all_users()
{
$this->assertNotNull($this->repository->all());
}
public function test_create_user()
{
$this->assertTrue($this->repository->create($this->newUser()));
}
public function test_update_user()
{
// Arrange
$user = $this->newUser();
// Act
$this->repository->create($user);
$user->name = 'Jack';
// Assert
$this->assertTrue((integer)$this->repository->update($user) === 1);
}
public function test_delete_user()
{
// Arrange
$user = $this->newUser();
// Act
$this->repository->create($user);
// Assert
$this->assertTrue((integer)$this->repository->delete($user) === 1);
}
public function test_find_user()
{
// Arrange
$user = $this->newUser();
// Act
$this->repository->create($user);
// Assert
$this->assertInstanceOf(User::class, $this->repository->find($user->id));
}
}
不要在测试用例中覆盖 __construct()
。
测试用例是在早期实例化的,并且还依赖于您不调用的PHPUnit_Framework_TestCase
constructor。 DB
的自动加载器此时可能尚未初始化。
改用 setUp()
,它在每次测试之前都会被调用,并且是为这种初始化而设计的:
protected function setUp()
{
$this->repository = new UserRepository();
}