Php 是否可以从pl/pgsql返回嵌套记录?

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:

我在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: "^/$"}
    ]
}
其中角色来自表角色和用户角色,权限来自表权限和用户权限。通过
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());
});