在 Laravel 中与 DB Facade 的接口
Interface with DB Facade in Laravel
首先,如果这是一个愚蠢的问题,我深表歉意。我最近读了一篇关于存储库设计模式的文章,在为 Laravel Query Builder (Illuminate\Support\Facades\DB) 进行接口实现时遇到问题。
DatabaseService.php
use Modules\Core\Interfaces\IDatabase;
use \DB;
class DatabaseService implements IDatabase
{
protected $db;
public function __construct(DB $db)
{
$this->db = $db;
}
public function select($str)
{
$this->db::select($str);
return $this->db;
}
public function table($tableName)
{
$this->db::table($tableName);
return $this->db;
}
...
}
IDatabase.php
<?php namespace Modules\Core\Interfaces;
interface IDatabase
{
public function select($str);
public function table($tableName);
public function raw($rawQuery);
public function transaction($callback);
public function first();
public function get();
}
CoreServiceProvider.php
...
public function register()
{
...
$this->app->bind('Modules\Core\Interfaces\IDatabase', function($app) {
$db = $app->make(DB::class);
return new DatabaseService($db);
});
...
}
MailboxRepository.php
<?php namespace Modules\Mailbox\Repositories;
use Illuminate\Database\Eloquent\Model;
use Modules\Core\Interfaces\IDatabase;
use Modules\Mailbox\Interfaces\IMailbox;
class MailboxRepository implements IMailbox
{
public function __construct(..., IDatabase $db)
{
...
$this->db = $db;
}
...
public function getBadges()
{
$badges = $this->db->table('mailbox as a')
->select($this->db->raw(
"SUM(a.type = 'inbox') as inbox,
SUM(a.is_read = 0 AND a.type = 'inbox') as unread,
SUM(a.type = 'sent') as sent,
SUM(a.type = 'draft') as draft,
SUM(a.type = 'outbox') as outbox,
SUM(a.type = 'spam') as spam,
SUM(a.type = 'trash') as trash,
SUM(a.is_starred = 1) as starred"
))
->first();
return $badges;
}
...
}
MailboxServiceProvider.php
<?php namespace Modules\Mailbox;
...
use Modules\Mailbox\Interfaces\IMailbox;
use Modules\Mailbox\Repositories\MailboxRepository;
use Modules\Core\Interfaces\IDatabase;
use Illuminate\Support\ServiceProvider;
class MailboxServiceProvider extends ServiceProvider
{
protected $defer = true;
public function register()
{
$this->app->bind(IMailbox::class, function($app) {
return new MailboxRepository(
..., $app->make(IDatabase::class)
);
});
}
public function provides()
{
return [IMailbox::class];
}
}
有错误信息:
[2018-01-31 13:45:04] local.ERROR: Call to undefined method Illuminate\Support\Facades\DB::select()
{"userId":1,"email":"info@narpandi.com","exception":"[object]
(Symfony\Component\Debug\Exception\FatalThrowableError(code: 0): Call
to undefined method Illuminate\Support\Facades\DB::select() at
/var/www/personal-
website/app/Modules/Mailbox/Repositories/MailboxRepository.php:86)
如何正确地做到这一点?感谢您的帮助。
我认为这不是常见的存储库模式,在存储库模式中,您尝试创建如下方法:
Object get(Object id);
void create(Object entity);
void update(Object entity);
void delete(Object entity);
编辑,尝试做一些类似文档的事情:Database
use Modules\Core\Interfaces\IDatabase;
use Illuminate\Support\Facades\DB;
class DatabaseService implements IDatabase
{
public function select($str, $args)
{
return DB::select($str, $args);
}
}
但我再说一遍,这看起来不像 repository
。
经过反复试验,我终于弄清楚该怎么做。如 中所述,您不能直接使用 facade DB,因此您需要显式传递位于 DB facade 后面的 class。
在我的例子中,我使用桥接模式和流畅的接口(CMIIW),所以我将提供两个版本:
- 无桥接模式
MailboxServiceProvider.php
<?php namespace Modules\Mailbox;
use Modules\Mailbox\Interfaces\IMailbox;
...
use Modules\Mailbox\Repositories\MailboxRepository;
use Illuminate\Support\ServiceProvider;
/* Use these instead of DB facade */
use Illuminate\Database\DatabaseManager;
use Illuminate\Database\Connectors\ConnectionFactory;
class MailboxServiceProvider extends ServiceProvider
{
protected $defer = true;
public function register()
{
$this->app->bind(IMailbox::class, function($app) {
return new MailboxRepository(
..., new DatabaseManager($app, new ConnectionFactory($app))
);
});
}
public function provides()
{
return [IMailbox::class];
}
}
MailboxRepository.php
<?php namespace Modules\Mailbox\Repositories;
use Illuminate\Database\DatabaseManager;
use Modules\Mailbox\Interfaces\IMailbox;
class MailboxRepository implements IMailbox
{
...
protected $db;
public function __construct(..., DatabaseManager $db)
{
...
$this->db = $db;
}
...
}
- 具有桥接模式和流畅的界面
CoreServiceProvider.php
<?php namespace Modules\Core;
....
use Modules\Core\Services\DatabaseService;
use Modules\Mailbox\Repositories\MailboxRepository;
use Modules\Core\Interfaces\IDatabase;
use Modules\Mailbox\Interfaces\IMailbox;
/* Use these instead of DB facade */
use Illuminate\Database\DatabaseManager;
use Illuminate\Database\Connectors\ConnectionFactory;
use Illuminate\Support\ServiceProvider;
class CoreServiceProvider extends ServiceProvider
{
public function register()
{
...
$this->app->bind(IDatabase::class, function($app) {
return new DatabaseService(new DatabaseManager($app, new ConnectionFactory($app)));
});
$this->app->bind(IMailbox::class, function($app) {
return new MailboxRepository(
..., $app->make(IDatabase::class)
);
});
...
}
}
DatabaseService.php
<?php namespace Modules\Core\Services;
use Modules\Core\Interfaces\IDatabase;
use Illuminate\Database\DatabaseManager;
class DatabaseService implements IDatabase
{
protected $db;
public function __construct(DatabaseManager $db)
{
$this->db = $db;
}
public function select($str)
{
$this->db = $this->db->select($str);
return $this->db;
}
public function table($tableName)
{
$this->db = $this->db->table($tableName);
return $this->db;
}
...
}
MailboxRepository.php
<?php namespace Modules\Mailbox\Repositories;
use Modules\Core\Interfaces\IDatabase;
use Modules\Mailbox\Interfaces\IMailbox;
class MailboxRepository implements IMailbox
{
...
protected $db;
public function __construct(..., IDatabase $db)
{
...
$this->db = $db;
}
...
}
首先,如果这是一个愚蠢的问题,我深表歉意。我最近读了一篇关于存储库设计模式的文章,在为 Laravel Query Builder (Illuminate\Support\Facades\DB) 进行接口实现时遇到问题。
DatabaseService.php
use Modules\Core\Interfaces\IDatabase;
use \DB;
class DatabaseService implements IDatabase
{
protected $db;
public function __construct(DB $db)
{
$this->db = $db;
}
public function select($str)
{
$this->db::select($str);
return $this->db;
}
public function table($tableName)
{
$this->db::table($tableName);
return $this->db;
}
...
}
IDatabase.php
<?php namespace Modules\Core\Interfaces;
interface IDatabase
{
public function select($str);
public function table($tableName);
public function raw($rawQuery);
public function transaction($callback);
public function first();
public function get();
}
CoreServiceProvider.php
...
public function register()
{
...
$this->app->bind('Modules\Core\Interfaces\IDatabase', function($app) {
$db = $app->make(DB::class);
return new DatabaseService($db);
});
...
}
MailboxRepository.php
<?php namespace Modules\Mailbox\Repositories;
use Illuminate\Database\Eloquent\Model;
use Modules\Core\Interfaces\IDatabase;
use Modules\Mailbox\Interfaces\IMailbox;
class MailboxRepository implements IMailbox
{
public function __construct(..., IDatabase $db)
{
...
$this->db = $db;
}
...
public function getBadges()
{
$badges = $this->db->table('mailbox as a')
->select($this->db->raw(
"SUM(a.type = 'inbox') as inbox,
SUM(a.is_read = 0 AND a.type = 'inbox') as unread,
SUM(a.type = 'sent') as sent,
SUM(a.type = 'draft') as draft,
SUM(a.type = 'outbox') as outbox,
SUM(a.type = 'spam') as spam,
SUM(a.type = 'trash') as trash,
SUM(a.is_starred = 1) as starred"
))
->first();
return $badges;
}
...
}
MailboxServiceProvider.php
<?php namespace Modules\Mailbox;
...
use Modules\Mailbox\Interfaces\IMailbox;
use Modules\Mailbox\Repositories\MailboxRepository;
use Modules\Core\Interfaces\IDatabase;
use Illuminate\Support\ServiceProvider;
class MailboxServiceProvider extends ServiceProvider
{
protected $defer = true;
public function register()
{
$this->app->bind(IMailbox::class, function($app) {
return new MailboxRepository(
..., $app->make(IDatabase::class)
);
});
}
public function provides()
{
return [IMailbox::class];
}
}
有错误信息:
[2018-01-31 13:45:04] local.ERROR: Call to undefined method Illuminate\Support\Facades\DB::select()
{"userId":1,"email":"info@narpandi.com","exception":"[object]
(Symfony\Component\Debug\Exception\FatalThrowableError(code: 0): Call
to undefined method Illuminate\Support\Facades\DB::select() at
/var/www/personal-
website/app/Modules/Mailbox/Repositories/MailboxRepository.php:86)
如何正确地做到这一点?感谢您的帮助。
我认为这不是常见的存储库模式,在存储库模式中,您尝试创建如下方法:
Object get(Object id);
void create(Object entity);
void update(Object entity);
void delete(Object entity);
编辑,尝试做一些类似文档的事情:Database
use Modules\Core\Interfaces\IDatabase;
use Illuminate\Support\Facades\DB;
class DatabaseService implements IDatabase
{
public function select($str, $args)
{
return DB::select($str, $args);
}
}
但我再说一遍,这看起来不像 repository
。
经过反复试验,我终于弄清楚该怎么做。如 中所述,您不能直接使用 facade DB,因此您需要显式传递位于 DB facade 后面的 class。
在我的例子中,我使用桥接模式和流畅的接口(CMIIW),所以我将提供两个版本:
- 无桥接模式
MailboxServiceProvider.php
<?php namespace Modules\Mailbox;
use Modules\Mailbox\Interfaces\IMailbox;
...
use Modules\Mailbox\Repositories\MailboxRepository;
use Illuminate\Support\ServiceProvider;
/* Use these instead of DB facade */
use Illuminate\Database\DatabaseManager;
use Illuminate\Database\Connectors\ConnectionFactory;
class MailboxServiceProvider extends ServiceProvider
{
protected $defer = true;
public function register()
{
$this->app->bind(IMailbox::class, function($app) {
return new MailboxRepository(
..., new DatabaseManager($app, new ConnectionFactory($app))
);
});
}
public function provides()
{
return [IMailbox::class];
}
}
MailboxRepository.php
<?php namespace Modules\Mailbox\Repositories;
use Illuminate\Database\DatabaseManager;
use Modules\Mailbox\Interfaces\IMailbox;
class MailboxRepository implements IMailbox
{
...
protected $db;
public function __construct(..., DatabaseManager $db)
{
...
$this->db = $db;
}
...
}
- 具有桥接模式和流畅的界面
CoreServiceProvider.php
<?php namespace Modules\Core;
....
use Modules\Core\Services\DatabaseService;
use Modules\Mailbox\Repositories\MailboxRepository;
use Modules\Core\Interfaces\IDatabase;
use Modules\Mailbox\Interfaces\IMailbox;
/* Use these instead of DB facade */
use Illuminate\Database\DatabaseManager;
use Illuminate\Database\Connectors\ConnectionFactory;
use Illuminate\Support\ServiceProvider;
class CoreServiceProvider extends ServiceProvider
{
public function register()
{
...
$this->app->bind(IDatabase::class, function($app) {
return new DatabaseService(new DatabaseManager($app, new ConnectionFactory($app)));
});
$this->app->bind(IMailbox::class, function($app) {
return new MailboxRepository(
..., $app->make(IDatabase::class)
);
});
...
}
}
DatabaseService.php
<?php namespace Modules\Core\Services;
use Modules\Core\Interfaces\IDatabase;
use Illuminate\Database\DatabaseManager;
class DatabaseService implements IDatabase
{
protected $db;
public function __construct(DatabaseManager $db)
{
$this->db = $db;
}
public function select($str)
{
$this->db = $this->db->select($str);
return $this->db;
}
public function table($tableName)
{
$this->db = $this->db->table($tableName);
return $this->db;
}
...
}
MailboxRepository.php
<?php namespace Modules\Mailbox\Repositories;
use Modules\Core\Interfaces\IDatabase;
use Modules\Mailbox\Interfaces\IMailbox;
class MailboxRepository implements IMailbox
{
...
protected $db;
public function __construct(..., IDatabase $db)
{
...
$this->db = $db;
}
...
}