GraphQL WIP changing resolvers #2644

pull/2715/head
Angel Fernando Quiroz Campos 6 years ago
parent d456d1b8bc
commit cce857b58b
  1. 16
      config/packages/graphql.yaml
  2. 3
      config/services.yaml
  3. 6
      src/ApiBundle/GraphQL/Map/EnumMap.php
  4. 2
      src/ApiBundle/GraphQL/Map/MutationMap.php
  5. 166
      src/ApiBundle/GraphQL/Map/RootMap.php
  6. 2
      src/ApiBundle/GraphQL/Map/ScalarMap.php
  7. 2
      src/ApiBundle/GraphQL/Map/UserMap.php
  8. 54
      src/ApiBundle/GraphQL/Resolver/CourseDescriptionResolver.php
  9. 2
      src/ApiBundle/GraphQL/Resolver/CourseResolver.php
  10. 59
      src/ApiBundle/GraphQL/Resolver/CourseToolResolver.php
  11. 51
      src/ApiBundle/GraphQL/Resolver/CourseToolResolverTrait.php
  12. 9
      src/ApiBundle/GraphQL/Resolver/ToolAnnouncementsResolver.php
  13. 12
      src/ApiBundle/GraphQL/Resolver/ToolDescriptionResolver.php
  14. 9
      src/ApiBundle/GraphQL/Resources/config/Enum.types.yaml
  15. 89
      src/ApiBundle/GraphQL/Resources/config/Query.types.yaml
  16. 50
      src/ApiBundle/GraphQL/Resources/config/schema.types.graphql
  17. 18
      src/CoreBundle/Entity/Course.php

@ -4,13 +4,19 @@ overblog_graphql:
query: Query
mutation: Mutation
resolver_maps:
- Chamilo\ApiBundle\GraphQL\Map\RootResolverMap
- Chamilo\ApiBundle\GraphQL\Map\UserResolverMap
- Chamilo\ApiBundle\GraphQL\Map\EnumResolverMap
- Chamilo\ApiBundle\GraphQL\Map\ScalarResolverMap
- Chamilo\ApiBundle\GraphQL\Map\MutationResolverMap
- Chamilo\ApiBundle\GraphQL\Map\RootMap
- Chamilo\ApiBundle\GraphQL\Map\UserMap
- Chamilo\ApiBundle\GraphQL\Map\EnumMap
- Chamilo\ApiBundle\GraphQL\Map\ScalarMap
- Chamilo\ApiBundle\GraphQL\Map\MutationMap
mappings:
types:
-
type: graphql
dir: "%kernel.root_dir%/ApiBundle/GraphQL/Resources/config"
services:
Chamilo\ApiBundle\GraphQL\:
resource: "../../src/ApiBundle/GraphQL/*"
arguments:
- "@service_container"

@ -41,9 +41,6 @@ services:
arguments:
$debug: '%kernel.debug%'
Chamilo\ApiBundle\GraphQL\:
resource: "../src/ApiBundle/GraphQL/*"
Doctrine\ORM\EntityManager: "@doctrine.orm.default_entity_manager"
sylius_settings:

@ -13,7 +13,7 @@ use Symfony\Component\DependencyInjection\ContainerAwareInterface;
*
* @package Chamilo\ApiBundle\GraphQL\Map
*/
class EnumResolverMap extends ResolverMap implements ContainerAwareInterface
class EnumMap extends ResolverMap implements ContainerAwareInterface
{
use ApiGraphQLTrait;
@ -37,6 +37,10 @@ class EnumResolverMap extends ResolverMap implements ContainerAwareInterface
'SIZE_BIG' => ICON_SIZE_BIG,
'SIZE_HUGE' => ICON_SIZE_HUGE,
],
'CourseToolType' => [
'TOOL_COURSE_DESCRIPTION' => TOOL_COURSE_DESCRIPTION,
'TOOL_ANNOUNCEMENT' => TOOL_ANNOUNCEMENT,
],
];
}
}

@ -16,7 +16,7 @@ use Symfony\Component\DependencyInjection\ContainerAwareInterface;
*
* @package Chamilo\ApiBundle\GraphQL\Map
*/
class MutationResolverMap extends ResolverMap implements ContainerAwareInterface
class MutationMap extends ResolverMap implements ContainerAwareInterface
{
use ApiGraphQLTrait;

@ -4,6 +4,7 @@
namespace Chamilo\ApiBundle\GraphQL\Map;
use Chamilo\ApiBundle\GraphQL\ApiGraphQLTrait;
use Chamilo\ApiBundle\GraphQL\Resolver\ToolDescriptionResolver;
use Chamilo\CoreBundle\Entity\Course;
use Chamilo\CoreBundle\Entity\Message;
use Chamilo\CoreBundle\Entity\Session;
@ -12,6 +13,7 @@ use Chamilo\CoreBundle\Entity\SessionRelCourse;
use Chamilo\CoreBundle\Entity\SessionRelCourseRelUser;
use Chamilo\CoreBundle\Security\Authorization\Voter\CourseVoter;
use Chamilo\CoreBundle\Security\Authorization\Voter\SessionVoter;
use Chamilo\CourseBundle\Entity\CTool;
use Chamilo\UserBundle\Entity\User;
use GraphQL\Type\Definition\ResolveInfo;
use Overblog\GraphQLBundle\Definition\Argument;
@ -23,7 +25,7 @@ use Symfony\Component\DependencyInjection\ContainerAwareInterface;
* Class RootResolverMap
* @package Chamilo\ApiBundle\GraphQL\Map
*/
class RootResolverMap extends ResolverMap implements ContainerAwareInterface
class RootMap extends ResolverMap implements ContainerAwareInterface
{
use ApiGraphQLTrait;
@ -35,16 +37,12 @@ class RootResolverMap extends ResolverMap implements ContainerAwareInterface
return [
'Query' => [
self::RESOLVE_FIELD => function ($value, Argument $args, \ArrayObject $context, ResolveInfo $info) {
switch ($info->fieldName) {
case 'viewer':
return $this->resolveViewer();
case 'course':
return $this->resolveCourse($args['id']);
case 'session':
$this->resolveSession($args['id']);
case 'sessionCategory':
return $this->resolveSessionCategory($args['id']);
}
$context->offsetSet('course', null);
$context->offsetSet('session', null);
$method = 'resolve'.ucfirst($info->fieldName);
return $this->$method($args, $context);
},
],
'UserMessage' => [
@ -77,55 +75,86 @@ class RootResolverMap extends ResolverMap implements ContainerAwareInterface
},
],
'Course' => [
self::RESOLVE_FIELD => function (
Course $course,
Argument $args,
\ArrayObject $context,
ResolveInfo $info
) {
$context->offsetSet('course', $course);
switch ($info->fieldName) {
case 'picture':
return \CourseManager::getPicturePath($course, $args['fullSize']);
case 'teachers':
if ($context->offsetExists('session')) {
/** @var Session $session */
$session = $context->offsetGet('session');
if ($session) {
$coaches = [];
$coachSubscriptions = $session->getUserCourseSubscriptionsByStatus(
$course,
Session::COACH
);
/** @var SessionRelCourseRelUser $coachSubscription */
foreach ($coachSubscriptions as $coachSubscription) {
$coaches[] = $coachSubscription->getUser();
}
return $coaches;
}
'picture' => function (Course $course, Argument $args, \ArrayObject $context, ResolveInfo $info) {
return \CourseManager::getPicturePath($course, $args['fullSize']);
},
'teachers' => function (Course $course, Argument $args, \ArrayObject $context, ResolveInfo $info) {
if ($context->offsetExists('session')) {
/** @var Session $session */
$session = $context->offsetGet('session');
if ($session) {
$coaches = [];
$coachSubscriptions = $session->getUserCourseSubscriptionsByStatus(
$course,
Session::COACH
);
/** @var SessionRelCourseRelUser $coachSubscription */
foreach ($coachSubscriptions as $coachSubscription) {
$coaches[] = $coachSubscription->getUser();
}
$courseRepo = $this->em->getRepository('ChamiloCoreBundle:Course');
$teachers = $courseRepo
->getSubscribedTeachers($course)
->getQuery()
->getResult();
return $coaches;
}
}
return $teachers;
default:
$method = 'get'.ucfirst($info->fieldName);
$courseRepo = $this->em->getRepository('ChamiloCoreBundle:Course');
$teachers = $courseRepo
->getSubscribedTeachers($course)
->getQuery()
->getResult();
if (method_exists($course, $method)) {
return $course->$method();
}
return $teachers;
},
'tools' => function (Course $course, Argument $args, \ArrayObject $context, ResolveInfo $info) {
$session = null;
return null;
if ($context->offsetExists('session')) {
/** @var Session $session */
$session = $context->offsetGet('session');
}
}
$tools = $course->getTools($session);
if (!isset($args['type'])) {
return $tools;
}
return $tools->filter(
function (CTool $tool) use ($args) {
if ($tool->getName() === $args['type']) {
return true;
}
}
);
},
],
'CourseTool' => [
self::RESOLVE_TYPE => function (CTool $tool) {
switch ($tool->getName()) {
case TOOL_COURSE_DESCRIPTION:
return 'ToolDescription';
case TOOL_ANNOUNCEMENT:
default:
return 'ToolAnnouncements';
}
},
],
'ToolDescription' => [
'descriptions' => function (CTool $tool, Argument $args, \ArrayObject $context) {
$resolver = $this->container->get('Chamilo\ApiBundle\GraphQL\Resolver\ToolDescriptionResolver');
return $resolver->getDescriptions($tool, $context);
},
],
//'CourseDescription' => [],
'ToolAnnouncements' => [
'announcements' => function (CTool $tool, Argument $args, \ArrayObject $context) {
$resolver = $this->container->get('Chamilo\ApiBundle\GraphQL\Resolver\ToolAnnouncementsResolver');
return $resolver ? $resolver->getAnnouncements($tool, $context) : [];
},
],
'Session' => [
self::RESOLVE_FIELD => function (
@ -203,7 +232,7 @@ class RootResolverMap extends ResolverMap implements ContainerAwareInterface
/**
* @return User
*/
private function resolveViewer()
protected function resolveViewer()
{
$this->checkAuthorization();
@ -211,16 +240,20 @@ class RootResolverMap extends ResolverMap implements ContainerAwareInterface
}
/**
* @param int $id
* @param Argument $args
*
* @param \ArrayObject $context
*
* @return Course
*/
private function resolveCourse($id)
protected function resolveCourse(Argument $args, \ArrayObject $context)
{
$this->checkAuthorization();
$id = (int) $args['id'];
$courseRepo = $this->em->getRepository('ChamiloCoreBundle:Course');
$course = $courseRepo->find((int) $id);
$course = $courseRepo->find($id);
if (!$course) {
throw new UserError($this->translator->trans('Course not found.'));
@ -232,41 +265,46 @@ class RootResolverMap extends ResolverMap implements ContainerAwareInterface
throw new UserError($this->translator->trans('Not allowed'));
}
$context->offsetSet('course', $course);
return $course;
}
/**
* @param int $id
* @param Argument $args
* @param \ArrayObject $context
*
* @return Session
*/
private function resolveSession($id)
protected function resolveSession(Argument $args, \ArrayObject $context)
{
$this->checkAuthorization();
$sessionRepo = $this->em->getRepository('ChamiloCoreBundle:Session');
/** @var Session $session */
$session = $sessionRepo->find((int) $id);
$session = $sessionRepo->find($args['id']);
if (!$session) {
throw new UserError($this->translator->trans('Session not found.'));
}
$context->offsetSet('course', $session);
return $session;
}
/**
* @param int $id
* @param Argument $args
*
* @return SessionCategory
*/
private function resolveSessionCategory($id)
protected function resolveSessionCategory(Argument $args)
{
$this->checkAuthorization();
$repo = $this->em->getRepository('ChamiloCoreBundle:SessionCategory');
/** @var SessionCategory $category */
$category = $repo->find((int) $id);
$category = $repo->find($args['id']);
if (!$category) {
throw new UserError($this->translator->trans('Session category not found.'));

@ -15,7 +15,7 @@ use Symfony\Component\DependencyInjection\ContainerAwareInterface;
*
* @package Chamilo\ApiBundle\GraphQL\Map
*/
class ScalarResolverMap extends ResolverMap implements ContainerAwareInterface
class ScalarMap extends ResolverMap implements ContainerAwareInterface
{
use ApiGraphQLTrait;

@ -16,7 +16,7 @@ use Symfony\Component\DependencyInjection\ContainerAwareInterface;
*
* @package Chamilo\ApiBundle\GraphQL\Map
*/
class UserResolverMap extends ResolverMap implements ContainerAwareInterface
class UserMap extends ResolverMap implements ContainerAwareInterface
{
use ApiGraphQLTrait;

@ -1,54 +0,0 @@
<?php
/* For licensing terms, see /license.txt */
namespace Chamilo\ApiBundle\GraphQL\Resolver;
use Chamilo\ApiBundle\GraphQL\ApiGraphQLTrait;
use Chamilo\CourseBundle\Entity\CCourseDescription;
use GraphQL\Type\Definition\ResolveInfo;
use Overblog\GraphQLBundle\Definition\Argument;
use Overblog\GraphQLBundle\Definition\Resolver\ResolverInterface;
use Symfony\Component\DependencyInjection\ContainerAwareInterface;
/**
* Class CourseDescriptionResolver.
*
* @package Chamilo\ApiBundle\GraphQL\Resolver
*/
class CourseDescriptionResolver implements ResolverInterface, ContainerAwareInterface
{
use ApiGraphQLTrait;
/**
* @param CCourseDescription $description
* @param Argument $args
* @param ResolveInfo $info
* @param \ArrayObject $context
*/
public function __invoke(CCourseDescription $description, Argument $args, ResolveInfo $info, \ArrayObject $context)
{
$method = 'resolve'.ucfirst($info->fieldName);
if (method_exists($this, $method)) {
return $this->$method($description, $args, $context);
}
$method = 'get'.ucfirst($info->fieldName);
if (method_exists($description, $method)) {
return $description->$method();
}
return null;
}
/**
* @param CCourseDescription $description
*
* @return int
*/
public function resolveType(CCourseDescription $description)
{
return $description->getDescriptionType();
}
}

@ -28,7 +28,7 @@ class CourseResolver implements ResolverInterface, ContainerAwareInterface
*
* @return array
*/
public function resolveTools(Course $course, Argument $args, \ArrayObject $context)
public function getTools(Course $course, Argument $args, \ArrayObject $context)
{
$sessionId = 0;

@ -1,59 +0,0 @@
<?php
/* For licensing terms, see /license.txt */
namespace Chamilo\ApiBundle\GraphQL\Resolver;
use Chamilo\ApiBundle\GraphQL\ApiGraphQLTrait;
use Chamilo\CourseBundle\Entity\CTool;
use Doctrine\ORM\EntityManager;
use Overblog\GraphQLBundle\Definition\Resolver\ResolverInterface;
use Overblog\GraphQLBundle\Resolver\TypeResolver;
use Symfony\Component\DependencyInjection\ContainerAwareInterface;
use Symfony\Component\Translation\TranslatorInterface;
/**
* Class CourseToolResolver.
*
* @package Chamilo\ApiBundle\GraphQL\Resolver
*/
class CourseToolResolver implements ResolverInterface, ContainerAwareInterface
{
use ApiGraphQLTrait;
/**
* @var TypeResolver
*/
private $typeResolver;
/**
* CourseToolResolver constructor.
*
* @param EntityManager $entityManager
* @param TranslatorInterface $translator
* @param TypeResolver $typeResolver
*/
public function __construct(
EntityManager $entityManager,
TranslatorInterface $translator,
TypeResolver $typeResolver
) {
$this->em = $entityManager;
$this->translator = $translator;
$this->typeResolver = $typeResolver;
}
/**
* @param CTool $tool
*
* @return \GraphQL\Type\Definition\Type
*/
public function __invoke(CTool $tool)
{
switch ($tool->getName()) {
case TOOL_COURSE_DESCRIPTION:
return $this->typeResolver->resolve('ToolDescription');
case TOOL_ANNOUNCEMENT:
return $this->typeResolver->resolve('ToolAnnouncements');
}
}
}

@ -1,51 +0,0 @@
<?php
/* For licensing terms, see /license.txt */
namespace Chamilo\ApiBundle\GraphQL\Resolver;
use Chamilo\CourseBundle\Entity\CTool;
use GraphQL\Type\Definition\ResolveInfo;
use Overblog\GraphQLBundle\Definition\Argument;
/**
* Trait CourseToolResolverTrait.
*
* @package Chamilo\ApiBundle\GraphQL\Resolver
*/
trait CourseToolResolverTrait
{
/**
* @param CTool $tool
* @param Argument $args
* @param ResolveInfo $info
* @param \ArrayObject $context
*
* @return mixed
*/
public function __invoke(CTool $tool, Argument $args, ResolveInfo $info, \ArrayObject $context)
{
$method = 'resolve'.ucfirst($info->fieldName);
if (method_exists($this, $method)) {
return $this->$method($tool, $args, $context);
}
$method = 'get'.ucfirst($info->fieldName);
if (method_exists($tool, $method)) {
return $tool->$method();
}
return null;
}
/**
* @param CTool $tool
*
* @return bool
*/
public function resolveIsVisible(CTool $tool): bool
{
return (bool) $tool->getVisibility();
}
}

@ -8,28 +8,25 @@ use Chamilo\CoreBundle\Entity\Course;
use Chamilo\CoreBundle\Entity\Session;
use Chamilo\CourseBundle\Entity\CTool;
use GraphQL\Error\UserError;
use Overblog\GraphQLBundle\Definition\Argument;
use Overblog\GraphQLBundle\Definition\Resolver\ResolverInterface;
use Symfony\Component\DependencyInjection\ContainerAwareInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
/**
* Class ToolAnnouncementsResolver.
*
* @package Chamilo\ApiBundle\GraphQL\Resolver
*/
class ToolAnnouncementsResolver implements ResolverInterface, ContainerAwareInterface
class ToolAnnouncementsResolver implements ContainerAwareInterface
{
use ApiGraphQLTrait;
use CourseToolResolverTrait;
/**
* @param CTool $tool
* @param Argument $args
* @param \ArrayObject $context
*
* @return array
*/
public function resolveAnnouncements(CTool $tool, Argument $args, \ArrayObject $context): array
public function getAnnouncements(CTool $tool, \ArrayObject $context): array
{
/** @var Course $course */
$course = $context->offsetGet('course');

@ -6,8 +6,6 @@ namespace Chamilo\ApiBundle\GraphQL\Resolver;
use Chamilo\ApiBundle\GraphQL\ApiGraphQLTrait;
use Chamilo\CoreBundle\Entity\Course;
use Chamilo\CourseBundle\Entity\CTool;
use Overblog\GraphQLBundle\Definition\Argument;
use Overblog\GraphQLBundle\Definition\Resolver\ResolverInterface;
use Symfony\Component\DependencyInjection\ContainerAwareInterface;
/**
@ -15,19 +13,17 @@ use Symfony\Component\DependencyInjection\ContainerAwareInterface;
*
* @package Chamilo\ApiBundle\GraphQL\Resolver
*/
class ToolDescriptionResolver implements ResolverInterface, ContainerAwareInterface
class ToolDescriptionResolver implements ContainerAwareInterface
{
use ApiGraphQLTrait;
use CourseToolResolverTrait;
/**
* @param CTool $tool
* @param Argument $args
* @param \ArrayObject $context
*
* @return array
*/
public function resolveDescriptions(CTool $tool, Argument $args, \ArrayObject $context): array
public function getDescriptions(CTool $tool, \ArrayObject $context): array
{
/** @var Course $course */
$course = $context->offsetGet('course');
@ -38,7 +34,9 @@ class ToolDescriptionResolver implements ResolverInterface, ContainerAwareInterf
/** @var Session $session */
$session = $context->offsetGet('session');
$cd->set_session_id($session->getId());
if ($session) {
$cd->set_session_id($session->getId());
}
}
$descriptions = $cd->get_description_data();

@ -1,9 +0,0 @@
CourseToolType:
type: enum
config:
description: 'One of the types of course tool'
values:
TOOL_DESCRIPTION:
value: '@=constant("TOOL_COURSE_DESCRIPTION")'
TOOL_ANNOUNCEMENT:
value: '@=constant("TOOL_ANNOUNCEMENT")'

@ -1,89 +0,0 @@
Course:
type: object
config:
description: 'A course registered on the platform.'
fields:
tools:
description: 'List of available tools for student view.'
type: '[CourseTool]'
args:
type:
description: 'Filter by one type of tool'
type: 'CourseToolType'
CourseTool:
type: union
config:
description: 'Course tools'
resolveType: '@=resolver("Chamilo\\ApiBundle\\GraphQL\\Resolver\\CourseToolResolver", [value])'
types: [ToolDescription, ToolAnnouncements]
ToolDescription:
type: object
config:
description: 'Global summary of the course.'
resolveField: '@=resolver("Chamilo\\ApiBundle\\GraphQL\\Resolver\\ToolDescriptionResolver", [value, args, info, context])'
fields:
name:
type: 'String'
category:
type: 'String'
image:
type: 'String'
customIcon:
type: 'String'
isVisible:
type: 'Boolean'
descriptions:
type: '[CourseDescription]!'
CourseDescription:
type: object
config:
description: 'A section for the course description.'
resolveField: '@=resolver("Chamilo\\ApiBundle\\GraphQL\\Resolver\\CourseDescriptionResolver", [value, args, info, context])'
fields:
id:
type: 'Int'
title:
type: 'String'
content:
type: 'String'
type:
type: 'Int'
ToolAnnouncements:
type: object
config:
description: 'Announcements related to the course.'
resolveField: '@=resolver("Chamilo\\ApiBundle\\GraphQL\\Resolver\\ToolAnnouncementsResolver", [value, args, info, context])'
fields:
name:
type: 'String'
category:
type: 'String'
image:
type: 'String'
customIcon:
type: 'String'
isVisible:
type: 'Boolean'
announcements:
type: '[CourseAnnouncement]!'
CourseAnnouncement:
type: object
config:
description: 'Course announcement.'
resolveField: '@=resolver("Chamilo\\ApiBundle\\GraphQL\\Resolver\\CourseAnnouncementResolver", [value, args, info, context])'
fields:
id:
type: 'Int'
title:
type: 'String'
content:
type: 'String'
by:
type: 'User'
lastUpdateDate:
type: 'DateTime'

@ -92,6 +92,46 @@ type Course {
): String
"Teachers list in course. Or tutors list from course in session."
teachers: [User!]
"List of available tools for student view."
tools(
"Filter by one type of tool"
type: CourseToolType
): [CourseTool!]
}
"Global summary of the course."
type ToolDescription {
name: String
category: String
image: String
customIcon: String
descriptions: [CourseDescription!]
}
"A section for the course description."
type CourseDescription {
id: Int
title: String
content: String
descriptionType: Int
}
"Announcements related to the course."
type ToolAnnouncements {
name: String
category: String
image: String
customIcon: String
announcements: [CourseAnnouncement!]
}
"A course announcement."
type CourseAnnouncement {
id: Int
title: String
content: String
author: User!
lastUpdateDate: DateTime
}
"A session registered on the platform."
@ -123,6 +163,10 @@ type SessionCategory {
endDate: DateTime
}
# Unions
union CourseTool = ToolDescription | ToolAnnouncements
# Enums
"One of the statuses for the user."
@ -153,6 +197,12 @@ enum ImageSize {
SIZE_HUGE
}
"One of the types of course tool"
enum CourseToolType {
TOOL_COURSE_DESCRIPTION
TOOL_ANNOUNCEMENT
}
# Scalars
scalar DateTime

@ -92,6 +92,8 @@ class Course
//protected $items;
/**
* @var ArrayCollection
*
* @ORM\OneToMany(targetEntity="Chamilo\CourseBundle\Entity\CTool", mappedBy="course", cascade={"persist", "remove"})
*/
protected $tools;
@ -383,11 +385,23 @@ class Course
}
/**
* @param Session $session
*
* @return ArrayCollection
*/
public function getTools()
public function getTools(Session $session = null)
{
return $this->tools;
$orWhere = Criteria::expr()->eq('sessionId', 0);
if ($session) {
$orWhere = Criteria::expr()->in('sessionId', [0, $session->getId()]);
}
$criteria = Criteria::create()
->where(Criteria::expr()->isNull('sessionId'))
->orWhere($orWhere);
return $this->tools->matching($criteria);
}
/**

Loading…
Cancel
Save