我在 pgsql 8.4 :
中有以下表格user
permission
role
user_permission (n:m)
role_permission (n:m)
user_role (n:1)
我有一个REST服务,GET /user/1
我必须从数据库中得到这样的东西:
{
id:1,
name: "John Smith",
roles: [
{id: 1, name: "Administrator"},
{id: 2, name: "Editor"}
],
permissions: [
{id: 1, method: "GET", resource: "^/$"}
]
}
角色来自桌子角色& user_role和权限来自表格权限& user_permission。通过PUT /user/1
我想将类似的数据发送到数据库。
是否可以使用pl / pgsql函数执行此操作,或者我必须编写简单查询,并从php逐个执行它们?
我不一定要将json发送到pgsql,如果这可以使用没有连接字符串的php数组等等,那就绰绰有余了。
我无法将服务器升级到更高版本。
关系映射对我不好,我使用存储过程来处理所有事情,因为我不想在php中编写sql模板。我只需要原始数据,我唯一要做的就是json_encode或json_decode,所以经典的ORM方式在这里没用,我认为因为我在数据库中的pl / pgsql函数中有业务逻辑,而php只是验证和转换消息
答案 0 :(得分:1)
请注意user
和role
是数据库保留字。
只需通过一个查询询问数据库您想要的内容:
SELECT
my_user.id
my_user.name,
array_agg(my_role) AS "roles",
array_agg(permission) AS "permissions"
FROM
"user" my_user
LEFT JOIN user_permission up ON my_user.id = up.user_id
LEFT JOIN permission ON up.permission_id = permission.id
LEFT JOIN user_role ur ON user.id = ur.user_id
LEFT JOIN "role" my_role ON my_role.id = ur.role_id
你会得到一个丑陋的字符串,带有dobule转义对象到数组中。使用Pomm层将允许您使用转换器直接从此查询中获取PHP对象的数组。
<?php
public function getUserPermissionsAndRoles($user_id)
{
$sql = <<<SQL
SELECT
:user_fields_as_my_user,
array_agg(my_role) AS "roles",
array_agg(permission) AS "permissions"
FROM
":user_table" my_user
LEFT JOIN :user_permission_table up ON my_user.id = up.user_id
LEFT JOIN :permission_table ON up.permission_id = permission.id
LEFT JOIN :user_role_table ur ON user.id = ur.user_id
LEFT JOIN ":role_table" my_role ON my_role.id = ur.role_id
WHERE
my_user.id = ?
SQL;
$sql = strtr($sql, array(
":user_fields_as_my_user" => $this->formatFieldsWithAlias('getSelectFields', 'my_user'),
":user_table" => $this->getTableName(),
":user_permission_table" => $this->getConnection()->getMapFor("\Db\App\UserPermission")->getTableName(),
":permission_table" => $this->getConnection()->getMapFor("\Db\App\Permission")->getTableName(),
":user_role_table" => $this->getConnection()->getMapFor("\Db\App\UserRole")->getTableName(),
":role_table" => $this->getConnection()->getMapFor("\Db\App\Role")->getTableName(),
));
return $this->query($sql, array($user_id));
}
为了告诉Pomm它可以是user_role,user_permission,permission和role数据库对象的转换器,在实例化数据库时,添加以下内容:
$database = new \Pomm\Database(array("dsn" => "pgsql://user:pass@host:port/db_name", "name" => "app"));
$cnct = $database->getConnection();
$database
->registerConverter('UserPermission', new \Pomm\Converter\PgEntity($cnct->getMapFor('\Db\App\UserPermission')), array('user_permission'))
->registerConverter('Permission', new \Pomm\Converter\PgEntity($cnct->getMapFor('\Db\App\Permission')), array('permission'))
->registerConverter('UserRole', new \Pomm\Converter\PgEntity($cnct->getMapFor('\Db\App\UserRole')), array('user_role'))
->registerConverter('Role', new \Pomm\Converter\PgEntity($cnct->getMapFor('\Db\App\Role')), array('role'))
;
现在数据库知道可以使用这些转换器,但UserMap
必须知道何时解析名为“roles”和“permissions”的结果字段,它必须将它们作为Role
的数组处理和Permission
个实体。这就是initialize()
类的UserMap
函数代表的含义:
<?php
class UserMap extends \Db\App\Base\UserMap
{
public function initialize()
{
parent::initialize();
$this->addVirtualField('roles', 'Role[]');
$this->addVirtualField('permissions', 'Permission[]');
}
现在,在您的控制器中,您只需调用模型的方法并将其转换为JSON响应:
<?php
$database = new \Pomm\Database(array("dsn" => "pgsql://user:pass@host:port/db_name", "name" => "app"));
$cnct = $database->getConnection();
$database
->registerConverter('UserPermission', new \Pomm\Converter\PgEntity($cnct->getMapFor('\Db\App\UserPermission')), array('user_permission'))
->registerConverter('Permission', new \Pomm\Converter\PgEntity($cnct->getMapFor('\Db\App\Permission')), array('permission'))
->registerConverter('UserRole', new \Pomm\Converter\PgEntity($cnct->getMapFor('\Db\App\UserRole')), array('user_role'))
->registerConverter('Role', new \Pomm\Converter\PgEntity($cnct->getMapFor('\Db\App\Role')), array('role'))
;
$collection = $cnct->getMapFor('\Db\App\User')
->getUserPermissionsAndRoles($_GET['user_id']) // <- get an iterator over fetched users with extra info.
;
echo json_encode($collection->extract()); // <- dump an array from the iterator and cast it to json.
当然,使用像Silex这样的微框架可以更简单地使用纯PHP部分,其控制器将是:
<?php //...
$app->get('/user/{user_id}', function($user_id) use ($app) {
$collection = $app['pomm.connection']
->getMapFor('\Db\App\User')
->getUserPermissionsAndRoles($user_id);
if ($collection->count() === 0)
{
$this->abort(404, sprintf("No such user '%s'.", $user_id));
}
return $app->json($collection->extract());
});
干杯!
答案 1 :(得分:1)
有可能:“Returning a nested composite type from a PL/pgSQL function”,但由于pgsql中没有内置的关联数组,因此很难将数据转换为php关联数组和json。所以我认为这里最好的解决方案是用多个查询读取数据并用php构建关联数组。
在pgsql 9.2中,使用json数据类型和自定义setof记录更容易做到这一点 - &gt; json聚合函数。在8.4我认为这不值得努力......