我刚刚开始在Laravel 5.5中使用database
会话驱动程序以及PostgreSQL,但我遇到了一些轻微的不便。
我想将last_activity
列保留为timestamp with timezone
,但是Laravel想要在其中写入一个整数,有时它也会尝试根据整数值从中删除。
我尝试在Session
模型中执行以下操作:
public function setLastActivityAttribute($ts){
$this->attributes['last_activity'] = date('c', $ts);
}
适用于保存,但是当Laravel尝试垃圾收集会话时,它会使用一个整数值来导致PDOException
:
SQLSTATE [22008]:日期时间字段溢出:7错误:日期/时间字段值超出范围:“1506794381”
提示:也许你需要一个不同的“日期风格”设置。 (SQL:从“sessions”中删除“last_activity”< = 1506794381)
我有什么方法可以指定格式或拦截流程以保留timestamptz
列类型吗?
答案 0 :(得分:2)
我建议通过覆盖DatabaseSessionHandler.php
驱动程序的gc
和expired
方法来创建自定义会话驱动程序,以使用timestamp with timezone
而不是整数。
gc
目前已通过time() - $lifetime
,但您可以将其更改为date('c', time() - $lifetime)
。在expired
中,您可以致电strtotime
上的$session->last_activity
转换为与getTimestamp()
相同的单位。
<?php
namespace App\Extensions;
use Illuminate\Session\DatabaseSessionHandler;
class MyPostgresHandler extends DatabaseSessionHandler
{
public function gc($lifetime) {
$sessions = $this->getQuery()->where('last_activity', '<=', date('c', time() - $lifetime))->get();
foreach ($sessions as $session) {
$this->destroy($session->id);
}
}
protected function expired($session)
{
return isset($session->last_activity) &&
strtotime($session->last_activity) < Carbon::now()->subMinutes($this->minutes)->getTimestamp();
}
}
然后您可以通过扩展ServiceProvider
<?php
namespace App\Providers;
use App\Extensions\MyPostgresHandler;
use Illuminate\Support\Facades\Session;
use Illuminate\Support\ServiceProvider;
class SessionServiceProvider extends ServiceProvider
{
/**
* Perform post-registration booting of services.
*
* @return void
*/
public function boot()
{
Session::extend('my-db-driver', function ($app) {
return new MyPostgresHandler;
});
}
/**
* Register bindings in the container.
*
* @return void
*/
public function register()
{
//
}
}
现在,您可以在my-db-driver
config/session.php
有关详细信息,请参阅https://laravel.com/docs/5.5/session#implementing-the-driver
从OP更新
在FuzzyTree's answer之上添加,需要添加的代码比文档所说的更多,所以我想发布其余的流程。因为我们正在扩展内置类,所以它与框架的其他部分有一些联系,但幸运的是有很多方法可以利用它们。最终的SessionServiceProvider如下所示:
namespace App\Providers;
use App\Extensions\MyPostgresHandler;
use Illuminate\Database\Connectors\PostgresConnector;
use Illuminate\Database\PostgresConnection;
use Illuminate\Support\Facades\Session;
use Illuminate\Support\ServiceProvider;
use Illuminate\Database\Connection;
class SessionServiceProvider extends ServiceProvider {
public function boot(){
Session::extend('postgres', function ($app){
return new MyPostgresHandler;
});
Connection::resolverFor('postgres', function ($connection, $database, $prefix, $config) {
return new PostgresConnection($connection, $database, $prefix, $config);
});
$this->app->bind('db.connector.postgres', function(){
return new PostgresConnector;
});
}
}
我已将我的驱动程序命名为postgres
,并且驱动程序的类与原始答案中的相同。由于缺少参数,我的IDE在return new MyPostgresHandler;
行显示错误,但似乎代码无论如何都有效。
这些解析器是Laravel其余部分接受我们的新驱动程序所必需的,因为内置类只将pgsql
名称映射到相应的类,因为我们创建了一个具有不同名称的驱动程序否则会认为它无效。
最后,服务提供商必须在config/app.php
注册:
'providers' => [
// ...
/*
* Application Service Providers...
*/
App\Providers\AppServiceProvider::class,
App\Providers\AuthServiceProvider::class,
App\Providers\EventServiceProvider::class,
App\Providers\RouteServiceProvider::class,
App\Providers\SessionServiceProvider::class, // <--
],