Be aware user
and role
are database reserved words.
Just ask the database what you want with one query:
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
And you will get an ugly string with dobule escaped objects into array. Using Pomm layer will allow you to use the converter to get arrays of PHP objects directly from this query.
<?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));
}
In order to tell Pomm it can be converter of user_role, user_permission, permission and role database objects, when instanciating your database, add the following :
$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'))
;
Now the database knows theses converters can be used but the UserMap
has to know when it parses a result field named "roles" and "permissions", it must handle them as an array of Role
and Permission
entities. This is what the initialize()
function of the UserMap
class stands for:
<?php
class UserMap extends \Db\App\Base\UserMap
{
public function initialize()
{
parent::initialize();
$this->addVirtualField('roles', 'Role[]');
$this->addVirtualField('permissions', 'Permission[]');
}
Now, in your controller you just have to call the model's method and cast it to a JSON response:
<?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.
Of course the pure PHP part would be a way easier with a micro-framework like Silex where your controller would be:
<?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());
});
Cheers !