Php 是否可以从pl/pgsql返回嵌套记录?
我在pgsql 8.4中有以下表格:Php 是否可以从pl/pgsql返回嵌套记录?,php,postgresql,plpgsql,postgresql-8.4,Php,Postgresql,Plpgsql,Postgresql 8.4,我在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:
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: "^/$"}
]
}
其中角色来自表角色和用户角色,权限来自表权限和用户权限。通过PUT/user/1
我想向数据库发送类似的数据
使用pl/pgsql函数可以做到这一点吗,或者我必须编写简单的查询,并从php中逐个执行它们
我不一定要将json发送到pgsql,如果这在没有连接字符串的php数组中是可能的,那么就足够了
我无法将服务器升级到更高版本
关系映射对我来说并不好,因为我不想用php编写sql模板,所以我什么都使用存储过程。我只需要原始数据,我唯一要做的就是json_编码或json_解码,所以经典的ORM方法在这里毫无用处,因为我在数据库中有pl/pgsql函数中的业务逻辑,php只是验证和转换消息。请注意
用户
和角色
是数据库保留字
只需通过一个查询询问数据库您想要什么:
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转义对象到数组中。使用层将允许您使用转换器直接从此查询获取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));
}
现在数据库知道可以使用这些转换器,但是UserMap
必须知道当它解析名为“角色”和“权限”的结果字段时,它必须将它们作为Role
和Permission
实体的数组来处理。这就是UserMap
类的initialize()
<?php
class UserMap extends \Db\App\Base\UserMap
{
public function initialize()
{
parent::initialize();
$this->addVirtualField('roles', 'Role[]');
$this->addVirtualField('permissions', 'Permission[]');
}
有可能:”,但由于pgsql中没有内置关联数组,因此很难再将数据转换为php关联数组和json。因此,我认为最好的解决方案是使用多个查询读取数据,并使用php构建关联数组
在PGSQL9.2中,使用json数据类型和自定义的一组记录->json聚合函数更容易做到这一点。在8.4中,我认为这不值得努力…谢谢!所以这是可能的,但我认为在3个单独的查询中获取数据更简单。顺便说一句,我会检查这个POMM,很高兴知道每个可能的解决方案…当我只向浏览器发送JSON数据时,我不需要真正的映射程序,这就是我使用存储过程的原因。我将编辑这个问题,因为我不想使用关系映射,这并不明显。Pomm不是ORM,因为它不获取关系数据。它是一个对象模型管理器(OMM),因为它不使用db抽象,而是使用数据库功能从SQL查询中提供面向对象的实体。我可以理解,您不需要这么高的层,但是,转换器在本例imho中非常有用。最初的问题是,是否可以使用简单的pg函数(或pdo)和pl/pgsql来实现这一点,因此不使用转换器(或使用非常小的转换器)?POMM太大了,我想,我正在寻找一个更简单的解决方案。。。
<?php
class UserMap extends \Db\App\Base\UserMap
{
public function initialize()
{
parent::initialize();
$this->addVirtualField('roles', 'Role[]');
$this->addVirtualField('permissions', 'Permission[]');
}
<?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.
<?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());
});