parent
fe334b013b
commit
e48dc568ac
@ -1,4 +1,4 @@ |
||||
Copyright (c) 2014-2017 Christian Flothmann |
||||
Copyright (c) 2016-2017 Christian Flothmann |
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy |
||||
of this software and associated documentation files (the "Software"), to deal |
||||
@ -0,0 +1,51 @@ |
||||
{ |
||||
"name": "php-xapi/lrs-bundle", |
||||
"type": "symfony-bundle", |
||||
"description": "Experience API (xAPI) Learning Record Store (LRS) based on the Symfony Framework", |
||||
"keywords": ["xAPI", "Experience API", "Tin Can API", "LRS", "Learning Record Store", "Symfony", "bundle"], |
||||
"homepage": "https://github.com/php-xapi/lrs-bundle", |
||||
"license": "MIT", |
||||
"authors": [ |
||||
{ |
||||
"name": "Christian Flothmann", |
||||
"homepage": "https://github.com/xabbuh" |
||||
}, |
||||
{ |
||||
"name": "Jérôme Parmentier", |
||||
"homepage": "https://github.com/Lctrs" |
||||
} |
||||
], |
||||
"require": { |
||||
"php": "^7.1", |
||||
"php-xapi/exception": "^0.1 || ^0.2", |
||||
"php-xapi/model": "^1.1 || ^2.0 || ^3.0", |
||||
"php-xapi/repository-api": "^0.3@dev || ^0.4@dev", |
||||
"php-xapi/serializer": "^1.0 || ^2.0", |
||||
"php-xapi/symfony-serializer": "^1.0 || ^2.0", |
||||
"symfony/config": "^3.4 || ^4.3", |
||||
"symfony/dependency-injection": "^3.4 || ^4.3", |
||||
"symfony/http-foundation": "^3.4 || ^4.3", |
||||
"symfony/http-kernel": "^3.4 || ^4.3" |
||||
}, |
||||
"require-dev": { |
||||
"phpspec/phpspec": "~2.3", |
||||
"php-xapi/json-test-fixtures": "^1.0 || ^2.0", |
||||
"php-xapi/test-fixtures": "^1.0.1", |
||||
"ramsey/uuid": "^2.9 || ^3.0" |
||||
}, |
||||
"autoload": { |
||||
"psr-4": { |
||||
"XApi\\LrsBundle\\": "src/" |
||||
} |
||||
}, |
||||
"autoload-dev": { |
||||
"psr-4": { |
||||
"spec\\XApi\\LrsBundle\\": "spec/" |
||||
} |
||||
}, |
||||
"extra": { |
||||
"branch-alias": { |
||||
"dev-master": "0.1.x-dev" |
||||
} |
||||
} |
||||
} |
||||
@ -0,0 +1,4 @@ |
||||
suites: |
||||
default: |
||||
namespace: XApi\LrsBundle |
||||
psr4_prefix: XApi\LrsBundle |
||||
@ -0,0 +1,197 @@ |
||||
<?php |
||||
|
||||
namespace spec\XApi\LrsBundle\Controller; |
||||
|
||||
use PhpSpec\ObjectBehavior; |
||||
use Prophecy\Argument; |
||||
use Symfony\Component\HttpFoundation\Request; |
||||
use Symfony\Component\HttpFoundation\ResponseHeaderBag; |
||||
use Xabbuh\XApi\Common\Exception\NotFoundException; |
||||
use Xabbuh\XApi\DataFixtures\StatementFixtures; |
||||
use Xabbuh\XApi\Model\StatementId; |
||||
use Xabbuh\XApi\Model\StatementResult; |
||||
use Xabbuh\XApi\Model\StatementsFilter; |
||||
use Xabbuh\XApi\Serializer\StatementResultSerializerInterface; |
||||
use Xabbuh\XApi\Serializer\StatementSerializerInterface; |
||||
use XApi\Fixtures\Json\StatementJsonFixtures; |
||||
use XApi\Fixtures\Json\StatementResultJsonFixtures; |
||||
use XApi\LrsBundle\Model\StatementsFilterFactory; |
||||
use XApi\Repository\Api\StatementRepositoryInterface; |
||||
|
||||
class StatementGetControllerSpec extends ObjectBehavior |
||||
{ |
||||
function let(StatementRepositoryInterface $repository, StatementSerializerInterface $statementSerializer, StatementResultSerializerInterface $statementResultSerializer, StatementsFilterFactory $statementsFilterFactory) |
||||
{ |
||||
$statement = StatementFixtures::getAllPropertiesStatement(); |
||||
$voidedStatement = StatementFixtures::getVoidingStatement()->withStored(new \DateTime()); |
||||
$statementCollection = StatementFixtures::getStatementCollection(); |
||||
$statementsFilter = new StatementsFilter(); |
||||
|
||||
$statementsFilterFactory->createFromParameterBag(Argument::type('\Symfony\Component\HttpFoundation\ParameterBag'))->willReturn($statementsFilter); |
||||
|
||||
$repository->findStatementById(StatementId::fromString(StatementFixtures::DEFAULT_STATEMENT_ID))->willReturn($statement); |
||||
$repository->findVoidedStatementById(StatementId::fromString(StatementFixtures::DEFAULT_STATEMENT_ID))->willReturn($voidedStatement); |
||||
$repository->findStatementsBy($statementsFilter)->willReturn($statementCollection); |
||||
|
||||
$statementSerializer->serializeStatement(Argument::type('\Xabbuh\XApi\Model\Statement'))->willReturn(StatementJsonFixtures::getTypicalStatement()); |
||||
|
||||
$statementResultSerializer->serializeStatementResult(Argument::type('\Xabbuh\XApi\Model\StatementResult'))->willReturn(StatementResultJsonFixtures::getStatementResult()); |
||||
|
||||
$this->beConstructedWith($repository, $statementSerializer, $statementResultSerializer, $statementsFilterFactory); |
||||
} |
||||
|
||||
function it_throws_a_badrequesthttpexception_if_the_request_has_given_statement_id_and_voided_statement_id() |
||||
{ |
||||
$request = new Request(); |
||||
$request->query->set('statementId', StatementFixtures::DEFAULT_STATEMENT_ID); |
||||
$request->query->set('voidedStatementId', StatementFixtures::DEFAULT_STATEMENT_ID); |
||||
|
||||
$this |
||||
->shouldThrow('\Symfony\Component\HttpKernel\Exception\BadRequestHttpException') |
||||
->during('getStatement', array($request)); |
||||
} |
||||
|
||||
function it_throws_a_badrequesthttpexception_if_the_request_has_statement_id_and_format_and_attachements_and_any_other_parameters() |
||||
{ |
||||
$request = new Request(); |
||||
$request->query->set('statementId', StatementFixtures::DEFAULT_STATEMENT_ID); |
||||
$request->query->set('format', 'ids'); |
||||
$request->query->set('attachments', false); |
||||
$request->query->set('related_agents', false); |
||||
|
||||
$this |
||||
->shouldThrow('\Symfony\Component\HttpKernel\Exception\BadRequestHttpException') |
||||
->during('getStatement', array($request)); |
||||
} |
||||
|
||||
function it_throws_a_badrequesthttpexception_if_the_request_has_voided_statement_id_and_format_and_any_other_parameters_except_attachments() |
||||
{ |
||||
$request = new Request(); |
||||
$request->query->set('voidedStatementId', StatementFixtures::DEFAULT_STATEMENT_ID); |
||||
$request->query->set('format', 'ids'); |
||||
$request->query->set('related_agents', false); |
||||
|
||||
$this |
||||
->shouldThrow('\Symfony\Component\HttpKernel\Exception\BadRequestHttpException') |
||||
->during('getStatement', array($request)); |
||||
} |
||||
|
||||
function it_throws_a_badrequesthttpexception_if_the_request_has_statement_id_and_attachments_and_any_other_parameters_except_format() |
||||
{ |
||||
$request = new Request(); |
||||
$request->query->set('statementId', StatementFixtures::DEFAULT_STATEMENT_ID); |
||||
$request->query->set('attachments', false); |
||||
$request->query->set('related_agents', false); |
||||
|
||||
$this |
||||
->shouldThrow('\Symfony\Component\HttpKernel\Exception\BadRequestHttpException') |
||||
->during('getStatement', array($request)); |
||||
} |
||||
|
||||
function it_throws_a_badrequesthttpexception_if_the_request_has_voided_statement_id_and_any_other_parameters_except_format_and_attachments() |
||||
{ |
||||
$request = new Request(); |
||||
$request->query->set('voidedStatementId', StatementFixtures::DEFAULT_STATEMENT_ID); |
||||
$request->query->set('related_agents', false); |
||||
|
||||
$this |
||||
->shouldThrow('\Symfony\Component\HttpKernel\Exception\BadRequestHttpException') |
||||
->during('getStatement', array($request)); |
||||
} |
||||
|
||||
function it_sets_a_X_Experience_API_Consistent_Through_header_to_the_response() |
||||
{ |
||||
$request = new Request(); |
||||
$request->query->set('statementId', StatementFixtures::DEFAULT_STATEMENT_ID); |
||||
|
||||
$response = $this->getStatement($request); |
||||
|
||||
/** @var ResponseHeaderBag $headers */ |
||||
$headers = $response->headers; |
||||
|
||||
$headers->has('X-Experience-API-Consistent-Through')->shouldBe(true); |
||||
} |
||||
|
||||
function it_includes_a_Last_Modified_Header_if_a_single_statement_is_fetched() |
||||
{ |
||||
$request = new Request(); |
||||
$request->query->set('statementId', StatementFixtures::DEFAULT_STATEMENT_ID); |
||||
|
||||
$response = $this->getStatement($request); |
||||
|
||||
/** @var ResponseHeaderBag $headers */ |
||||
$headers = $response->headers; |
||||
|
||||
$headers->has('Last-Modified')->shouldBe(true); |
||||
|
||||
$request = new Request(); |
||||
$request->query->set('voidedStatementId', StatementFixtures::DEFAULT_STATEMENT_ID); |
||||
|
||||
$response = $this->getStatement($request); |
||||
|
||||
/** @var ResponseHeaderBag $headers */ |
||||
$headers = $response->headers; |
||||
|
||||
$headers->has('Last-Modified')->shouldBe(true); |
||||
} |
||||
|
||||
function it_returns_a_multipart_response_if_attachments_parameter_is_true() |
||||
{ |
||||
$request = new Request(); |
||||
$request->query->set('attachments', true); |
||||
|
||||
$this->getStatement($request)->shouldReturnAnInstanceOf('XApi\LrsBundle\Response\MultipartResponse'); |
||||
} |
||||
|
||||
function it_returns_a_jsonresponse_if_attachments_parameter_is_false_or_not_set() |
||||
{ |
||||
$request = new Request(); |
||||
|
||||
$this->getStatement($request)->shouldReturnAnInstanceOf('\Symfony\Component\HttpFoundation\JsonResponse'); |
||||
|
||||
$request->query->set('attachments', false); |
||||
|
||||
$this->getStatement($request)->shouldReturnAnInstanceOf('\Symfony\Component\HttpFoundation\JsonResponse'); |
||||
} |
||||
|
||||
function it_should_fetch_a_statement(StatementRepositoryInterface $repository) |
||||
{ |
||||
$request = new Request(); |
||||
$request->query->set('statementId', StatementFixtures::DEFAULT_STATEMENT_ID); |
||||
|
||||
$repository->findStatementById(StatementId::fromString(StatementFixtures::DEFAULT_STATEMENT_ID))->shouldBeCalled(); |
||||
|
||||
$this->getStatement($request); |
||||
} |
||||
|
||||
function it_should_fetch_a_voided_statement_id(StatementRepositoryInterface $repository) |
||||
{ |
||||
$request = new Request(); |
||||
$request->query->set('voidedStatementId', StatementFixtures::DEFAULT_STATEMENT_ID); |
||||
|
||||
$repository->findVoidedStatementById(StatementId::fromString(StatementFixtures::DEFAULT_STATEMENT_ID))->shouldBeCalled(); |
||||
|
||||
$this->getStatement($request); |
||||
} |
||||
|
||||
function it_should_filter_all_statements_if_no_statement_id_or_voided_statement_id_is_provided(StatementRepositoryInterface $repository) |
||||
{ |
||||
$request = new Request(); |
||||
|
||||
$repository->findStatementsBy(Argument::type('\Xabbuh\XApi\Model\StatementsFilter'))->shouldBeCalled(); |
||||
|
||||
$this->getStatement($request); |
||||
} |
||||
|
||||
function it_should_build_an_empty_statement_result_response_if_no_statement_is_found(StatementRepositoryInterface $repository, StatementResultSerializerInterface $statementResultSerializer) |
||||
{ |
||||
$request = new Request(); |
||||
$request->query->set('statementId', StatementFixtures::DEFAULT_STATEMENT_ID); |
||||
|
||||
$repository->findStatementById(StatementId::fromString(StatementFixtures::DEFAULT_STATEMENT_ID))->willThrow('\Xabbuh\XApi\Common\Exception\NotFoundException'); |
||||
|
||||
$statementResultSerializer->serializeStatementResult(new StatementResult(array()))->shouldBeCalled()->willReturn(StatementResultJsonFixtures::getStatementResult()); |
||||
|
||||
$this->getStatement($request); |
||||
} |
||||
} |
||||
@ -0,0 +1,106 @@ |
||||
<?php |
||||
|
||||
namespace spec\XApi\LrsBundle\Controller; |
||||
|
||||
use PhpSpec\ObjectBehavior; |
||||
use Symfony\Component\HttpFoundation\Request; |
||||
use Xabbuh\XApi\Common\Exception\NotFoundException; |
||||
use Xabbuh\XApi\DataFixtures\StatementFixtures; |
||||
use Xabbuh\XApi\Model\StatementId; |
||||
use XApi\Repository\Api\StatementRepositoryInterface; |
||||
|
||||
class StatementPutControllerSpec extends ObjectBehavior |
||||
{ |
||||
function let(StatementRepositoryInterface $repository) |
||||
{ |
||||
$this->beConstructedWith($repository); |
||||
} |
||||
|
||||
function it_throws_a_badrequesthttpexception_if_a_statement_id_is_not_part_of_a_put_request() |
||||
{ |
||||
$statement = StatementFixtures::getTypicalStatement(); |
||||
$request = new Request(); |
||||
|
||||
$this |
||||
->shouldThrow('\Symfony\Component\HttpKernel\Exception\BadRequestHttpException') |
||||
->during('putStatement', array($request, $statement)); |
||||
} |
||||
|
||||
function it_throws_a_badrequesthttpexception_if_the_given_statement_id_as_part_of_a_put_request_is_not_a_valid_uuid() |
||||
{ |
||||
$statement = StatementFixtures::getTypicalStatement(); |
||||
$request = new Request(); |
||||
$request->query->set('statementId', 'invalid-uuid'); |
||||
|
||||
$this |
||||
->shouldThrow('\Symfony\Component\HttpKernel\Exception\BadRequestHttpException') |
||||
->during('putStatement', array($request, $statement)); |
||||
} |
||||
|
||||
function it_stores_a_statement_and_returns_a_204_response_if_the_statement_did_not_exist_before(StatementRepositoryInterface $repository) |
||||
{ |
||||
$statement = StatementFixtures::getTypicalStatement(); |
||||
$request = new Request(); |
||||
$request->query->set('statementId', $statement->getId()->getValue()); |
||||
|
||||
$repository->findStatementById($statement->getId())->willThrow(new NotFoundException('')); |
||||
$repository->storeStatement($statement, true)->shouldBeCalled(); |
||||
|
||||
$response = $this->putStatement($request, $statement); |
||||
|
||||
$response->shouldHaveType('Symfony\Component\HttpFoundation\Response'); |
||||
$response->getStatusCode()->shouldReturn(204); |
||||
} |
||||
|
||||
function it_throws_a_conflicthttpexception_if_the_id_parameter_and_the_statement_id_do_not_match_during_a_put_request() |
||||
{ |
||||
$statement = StatementFixtures::getTypicalStatement(); |
||||
$statementId = StatementId::fromString('39e24cc4-69af-4b01-a824-1fdc6ea8a3af'); |
||||
$request = new Request(); |
||||
$request->query->set('statementId', $statementId->getValue()); |
||||
|
||||
$this |
||||
->shouldThrow('\Symfony\Component\HttpKernel\Exception\ConflictHttpException') |
||||
->during('putStatement', array($request, $statement)); |
||||
} |
||||
|
||||
function it_uses_id_parameter_in_put_request_if_statement_id_is_null(StatementRepositoryInterface $repository) |
||||
{ |
||||
$statement = StatementFixtures::getTypicalStatement(); |
||||
$statementId = $statement->getId(); |
||||
$statement = $statement->withId(null); |
||||
$request = new Request(); |
||||
$request->query->set('statementId', $statementId->getValue()); |
||||
|
||||
$repository->findStatementById($statementId)->willReturn($statement); |
||||
$repository->findStatementById($statementId)->shouldBeCalled(); |
||||
|
||||
$this->putStatement($request, $statement); |
||||
} |
||||
|
||||
function it_does_not_override_an_existing_statement(StatementRepositoryInterface $repository) |
||||
{ |
||||
$statement = StatementFixtures::getTypicalStatement(); |
||||
$request = new Request(); |
||||
$request->query->set('statementId', $statement->getId()->getValue()); |
||||
|
||||
$repository->findStatementById($statement->getId())->willReturn($statement); |
||||
$repository->storeStatement($statement, true)->shouldNotBeCalled(); |
||||
|
||||
$this->putStatement($request, $statement); |
||||
} |
||||
|
||||
function it_throws_a_conflicthttpexception_if_an_existing_statement_with_the_same_id_is_not_equal_during_a_put_request(StatementRepositoryInterface $repository) |
||||
{ |
||||
$statement = StatementFixtures::getTypicalStatement(); |
||||
$existingStatement = StatementFixtures::getAttachmentStatement()->withId($statement->getId()); |
||||
$request = new Request(); |
||||
$request->query->set('statementId', $statement->getId()->getValue()); |
||||
|
||||
$repository->findStatementById($statement->getId())->willReturn($existingStatement); |
||||
|
||||
$this |
||||
->shouldThrow('\Symfony\Component\HttpKernel\Exception\ConflictHttpException') |
||||
->during('putStatement', array($request, $statement)); |
||||
} |
||||
} |
||||
@ -0,0 +1,18 @@ |
||||
<?php |
||||
|
||||
namespace spec\XApi\LrsBundle\DependencyInjection; |
||||
|
||||
use PhpSpec\ObjectBehavior; |
||||
|
||||
class XApiLrsExtensionSpec extends ObjectBehavior |
||||
{ |
||||
function it_is_a_di_extension() |
||||
{ |
||||
$this->shouldHaveType('Symfony\Component\DependencyInjection\Extension\ExtensionInterface'); |
||||
} |
||||
|
||||
function its_alias_is_xapi_lrs() |
||||
{ |
||||
$this->getAlias()->shouldReturn('xapi_lrs'); |
||||
} |
||||
} |
||||
@ -0,0 +1,160 @@ |
||||
<?php |
||||
|
||||
namespace spec\XApi\LrsBundle\EventListener; |
||||
|
||||
use PhpSpec\ObjectBehavior; |
||||
use Symfony\Component\HttpFoundation\FileBag; |
||||
use Symfony\Component\HttpFoundation\HeaderBag; |
||||
use Symfony\Component\HttpFoundation\ParameterBag; |
||||
use Symfony\Component\HttpFoundation\Request; |
||||
use Symfony\Component\HttpFoundation\ServerBag; |
||||
use Symfony\Component\HttpKernel\Event\GetResponseEvent; |
||||
|
||||
class AlternateRequestSyntaxListenerSpec extends ObjectBehavior |
||||
{ |
||||
function let(GetResponseEvent $event, Request $request, ParameterBag $query, ParameterBag $post, ParameterBag $attributes, HeaderBag $headers) |
||||
{ |
||||
$query->count()->willReturn(1); |
||||
$query->get('method')->willReturn('GET'); |
||||
|
||||
$post->getIterator()->willReturn(new \ArrayIterator()); |
||||
$post->get('content')->willReturn(null); |
||||
|
||||
$attributes->has('xapi_lrs.route')->willReturn(true); |
||||
|
||||
$request->query = $query; |
||||
$request->request = $post; |
||||
$request->attributes = $attributes; |
||||
$request->headers = $headers; |
||||
$request->getMethod()->willReturn('POST'); |
||||
|
||||
$event->isMasterRequest()->willReturn(true); |
||||
$event->getRequest()->willReturn($request); |
||||
} |
||||
|
||||
function it_returns_null_if_request_is_not_master(GetResponseEvent $event) |
||||
{ |
||||
$event->isMasterRequest()->willReturn(false); |
||||
$event->getRequest()->shouldNotBeCalled(); |
||||
|
||||
$this->onKernelRequest($event)->shouldReturn(null); |
||||
} |
||||
|
||||
function it_returns_null_if_request_has_no_attribute_xapi_lrs_route(GetResponseEvent $event, ParameterBag $attributes) |
||||
{ |
||||
$attributes->has('xapi_lrs.route')->shouldBeCalled()->willReturn(false); |
||||
|
||||
$this->onKernelRequest($event)->shouldReturn(null); |
||||
} |
||||
|
||||
function it_returns_null_if_request_method_is_get(GetResponseEvent $event, Request $request, ParameterBag $query) |
||||
{ |
||||
$query->get('method')->shouldNotBeCalled(); |
||||
$request->getMethod()->willReturn('GET'); |
||||
|
||||
$this->onKernelRequest($event)->shouldReturn(null); |
||||
} |
||||
|
||||
function it_returns_null_if_request_method_is_put(GetResponseEvent $event, Request $request, ParameterBag $query) |
||||
{ |
||||
$query->get('method')->shouldNotBeCalled(); |
||||
$request->getMethod()->willReturn('PUT'); |
||||
|
||||
$this->onKernelRequest($event)->shouldReturn(null); |
||||
} |
||||
|
||||
function it_throws_a_badrequesthttpexception_if_other_query_parameter_than_method_is_set(GetResponseEvent $event, ParameterBag $query) |
||||
{ |
||||
$query->count()->shouldBeCalled()->willReturn(2); |
||||
|
||||
$this |
||||
->shouldThrow('\Symfony\Component\HttpKernel\Exception\BadRequestHttpException') |
||||
->during('onKernelRequest', array($event)); |
||||
} |
||||
|
||||
function it_sets_the_request_method_equals_to_method_query_parameter(GetResponseEvent $event, Request $request, ParameterBag $query) |
||||
{ |
||||
$query->remove('method')->shouldBeCalled(); |
||||
$request->setMethod('GET')->shouldBeCalled(); |
||||
|
||||
$this->onKernelRequest($event); |
||||
} |
||||
|
||||
function it_sets_defined_post_parameters_as_header(GetResponseEvent $event, Request $request, ParameterBag $query, ParameterBag $post, HeaderBag $headers) |
||||
{ |
||||
$request->setMethod('GET')->shouldBeCalled(); |
||||
$query->remove('method')->shouldBeCalled(); |
||||
|
||||
$headerList = array( |
||||
'Authorization' => 'Authorization', |
||||
'X-Experience-API-Version' => 'X-Experience-API-Version', |
||||
'Content-Type' => 'Content-Type', |
||||
'Content-Length' => 'Content-Length', |
||||
'If-Match' => 'If-Match', |
||||
'If-None-Match' => 'If-None-Match', |
||||
); |
||||
|
||||
$post->getIterator()->shouldBeCalled()->willReturn(new \ArrayIterator($headerList)); |
||||
|
||||
foreach ($headerList as $key => $value) { |
||||
$post->remove($key)->shouldBeCalled(); |
||||
|
||||
$headers->set($key, $value)->shouldBeCalled(); |
||||
} |
||||
|
||||
$this->onKernelRequest($event); |
||||
} |
||||
|
||||
function it_sets_other_post_parameters_as_query_parameters(GetResponseEvent $event, Request $request, ParameterBag $query, ParameterBag $post) |
||||
{ |
||||
$request->setMethod('GET')->shouldBeCalled(); |
||||
$query->remove('method')->shouldBeCalled(); |
||||
|
||||
$parameterList = array( |
||||
'token' => 'a-token', |
||||
'attachments' => true, |
||||
); |
||||
|
||||
$post->getIterator()->shouldBeCalled()->willReturn(new \ArrayIterator($parameterList)); |
||||
|
||||
foreach ($parameterList as $key => $value) { |
||||
$post->remove($key)->shouldBeCalled(); |
||||
|
||||
$query->set($key, $value)->shouldBeCalled(); |
||||
} |
||||
|
||||
$this->onKernelRequest($event); |
||||
} |
||||
|
||||
function it_sets_content_from_post_parameters(GetResponseEvent $event, Request $request, ParameterBag $query, ParameterBag $post, ParameterBag $attributes, ParameterBag $cookies, FileBag $files, ServerBag $server) |
||||
{ |
||||
$query->all()->shouldBeCalled()->willReturn(array()); |
||||
$query->remove('method')->shouldBeCalled(); |
||||
|
||||
$post->all()->shouldBeCalled()->willReturn(array()); |
||||
$post->get('content')->shouldBeCalled()->willReturn('a content'); |
||||
$post->remove('content')->shouldBeCalled(); |
||||
|
||||
$attributes->all()->shouldBeCalled()->willReturn(array()); |
||||
$cookies->all()->shouldBeCalled()->willReturn(array()); |
||||
$files->all()->shouldBeCalled()->willReturn(array()); |
||||
$server->all()->shouldBeCalled()->willReturn(array()); |
||||
|
||||
$request->setMethod('GET')->shouldBeCalled(); |
||||
$request->initialize( |
||||
array(), |
||||
array(), |
||||
array(), |
||||
array(), |
||||
array(), |
||||
array(), |
||||
'a content' |
||||
)->shouldBeCalled(); |
||||
|
||||
$request->cookies = $cookies; |
||||
$request->files = $files; |
||||
$request->server = $server; |
||||
|
||||
$this->onKernelRequest($event); |
||||
} |
||||
} |
||||
@ -0,0 +1,9 @@ |
||||
<?php |
||||
|
||||
namespace spec\XApi\LrsBundle\EventListener; |
||||
|
||||
use PhpSpec\ObjectBehavior; |
||||
|
||||
class ExceptionListenerSpec extends ObjectBehavior |
||||
{ |
||||
} |
||||
@ -0,0 +1,59 @@ |
||||
<?php |
||||
|
||||
namespace spec\XApi\LrsBundle\EventListener; |
||||
|
||||
use PhpSpec\ObjectBehavior; |
||||
use Symfony\Component\HttpFoundation\ParameterBag; |
||||
use Symfony\Component\HttpFoundation\Request; |
||||
use Symfony\Component\HttpKernel\Event\GetResponseEvent; |
||||
use Xabbuh\XApi\Serializer\StatementSerializerInterface; |
||||
use XApi\Fixtures\Json\StatementJsonFixtures; |
||||
|
||||
class SerializerListenerSpec extends ObjectBehavior |
||||
{ |
||||
function let(StatementSerializerInterface $statementSerializer, GetResponseEvent $event, Request $request, ParameterBag $attributes) |
||||
{ |
||||
$attributes->has('xapi_lrs.route')->willReturn(true); |
||||
|
||||
$request->attributes = $attributes; |
||||
|
||||
$event->getRequest()->willReturn($request); |
||||
|
||||
$this->beConstructedWith($statementSerializer); |
||||
} |
||||
|
||||
function it_returns_null_if_request_has_no_attribute_xapi_lrs_route(GetResponseEvent $event, ParameterBag $attributes) |
||||
{ |
||||
$attributes->has('xapi_lrs.route')->shouldBeCalled()->willReturn(false); |
||||
$attributes->get('xapi_serializer')->shouldNotBeCalled(); |
||||
|
||||
$this->onKernelRequest($event)->shouldReturn(null); |
||||
} |
||||
|
||||
function it_sets_unserialized_data_as_request_attributes(StatementSerializerInterface $statementSerializer, GetResponseEvent $event, Request $request, ParameterBag $attributes) |
||||
{ |
||||
$jsonString = StatementJsonFixtures::getTypicalStatement(); |
||||
|
||||
$statementSerializer->deserializeStatement($jsonString)->shouldBeCalled(); |
||||
|
||||
$attributes->get('xapi_serializer')->willReturn('statement'); |
||||
$attributes->set('statement', null)->shouldBeCalled(); |
||||
|
||||
$request->getContent()->shouldBeCalled()->willReturn($jsonString); |
||||
|
||||
$this->onKernelRequest($event); |
||||
} |
||||
|
||||
function it_throws_a_badrequesthttpexception_if_the_serializer_fails(StatementSerializerInterface $statementSerializer, GetResponseEvent $event, Request $request, ParameterBag $attributes) |
||||
{ |
||||
$statementSerializer->deserializeStatement(null)->shouldBeCalled()->willThrow('\Symfony\Component\Serializer\Exception\InvalidArgumentException'); |
||||
|
||||
$attributes->get('xapi_serializer')->willReturn('statement'); |
||||
|
||||
$request->attributes = $attributes; |
||||
|
||||
$this |
||||
->shouldThrow('\Symfony\Component\HttpKernel\Exception\BadRequestHttpException') |
||||
->during('onKernelRequest', array($event)); |
||||
} |
||||
} |
||||
@ -0,0 +1,102 @@ |
||||
<?php |
||||
|
||||
namespace spec\XApi\LrsBundle\EventListener; |
||||
|
||||
use PhpSpec\ObjectBehavior; |
||||
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag; |
||||
use Symfony\Component\HttpFoundation\HeaderBag; |
||||
use Symfony\Component\HttpFoundation\Request; |
||||
use Symfony\Component\HttpFoundation\Response; |
||||
use Symfony\Component\HttpKernel\Event\FilterResponseEvent; |
||||
use Symfony\Component\HttpKernel\Event\GetResponseEvent; |
||||
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException; |
||||
|
||||
class VersionListenerSpec extends ObjectBehavior |
||||
{ |
||||
function let(GetResponseEvent $getResponseEvent, FilterResponseEvent $filterResponseEvent, Request $request, ParameterBag $attributes, HeaderBag $requestHeaders) |
||||
{ |
||||
$attributes->has('xapi_lrs.route')->willReturn(true); |
||||
|
||||
$request->attributes = $attributes; |
||||
$request->headers = $requestHeaders; |
||||
|
||||
$getResponseEvent->isMasterRequest()->willReturn(true); |
||||
$getResponseEvent->getRequest()->willReturn($request); |
||||
|
||||
$filterResponseEvent->isMasterRequest()->willReturn(true); |
||||
$filterResponseEvent->getRequest()->willReturn($request); |
||||
} |
||||
|
||||
function it_returns_null_if_requests_are_not_master(GetResponseEvent $getResponseEvent, FilterResponseEvent $filterResponseEvent) |
||||
{ |
||||
$getResponseEvent->isMasterRequest()->willReturn(false); |
||||
$getResponseEvent->getRequest()->shouldNotBeCalled(); |
||||
|
||||
$this->onKernelRequest($getResponseEvent)->shouldReturn(null); |
||||
|
||||
$filterResponseEvent->isMasterRequest()->willReturn(false); |
||||
$filterResponseEvent->getRequest()->shouldNotBeCalled(); |
||||
|
||||
$this->onKernelResponse($filterResponseEvent)->shouldReturn(null); |
||||
} |
||||
|
||||
function it_returns_null_if_not_xapi_route(GetResponseEvent $getResponseEvent, FilterResponseEvent $filterResponseEvent, ParameterBag $attributes) |
||||
{ |
||||
$attributes->has('xapi_lrs.route')->shouldBeCalled()->willReturn(false); |
||||
|
||||
$this->onKernelRequest($getResponseEvent)->shouldReturn(null); |
||||
|
||||
$this->onKernelResponse($filterResponseEvent)->shouldReturn(null); |
||||
} |
||||
|
||||
function it_throws_a_badrequesthttpexception_if_no_X_Experience_API_Version_header_is_set(GetResponseEvent $getResponseEvent, HeaderBag $requestHeaders) |
||||
{ |
||||
$requestHeaders->get('X-Experience-API-Version')->shouldBeCalled()->willReturn(null); |
||||
|
||||
$this |
||||
->shouldThrow(new BadRequestHttpException('Missing required "X-Experience-API-Version" header.')) |
||||
->during('onKernelRequest', array($getResponseEvent)); |
||||
} |
||||
|
||||
function it_throws_a_badrequesthttpexception_if_specified_version_is_not_supported(GetResponseEvent $getResponseEvent, HeaderBag $requestHeaders) |
||||
{ |
||||
$requestHeaders->get('X-Experience-API-Version')->shouldBeCalled()->willReturn('0.9.5'); |
||||
|
||||
$this |
||||
->shouldThrow(new BadRequestHttpException('xAPI version "0.9.5" is not supported.')) |
||||
->during('onKernelRequest', array($getResponseEvent)); |
||||
|
||||
$requestHeaders->get('X-Experience-API-Version')->shouldBeCalled()->willReturn('1.1.0'); |
||||
|
||||
$this |
||||
->shouldThrow(new BadRequestHttpException('xAPI version "1.1.0" is not supported.')) |
||||
->during('onKernelRequest', array($getResponseEvent)); |
||||
} |
||||
|
||||
function it_normalizes_the_X_Experience_API_Version_header(GetResponseEvent $getResponseEvent, HeaderBag $requestHeaders) |
||||
{ |
||||
$requestHeaders->get('X-Experience-API-Version')->shouldBeCalled()->willReturn('1.0'); |
||||
$requestHeaders->set('X-Experience-API-Version', '1.0.0')->shouldBeCalled(); |
||||
|
||||
$this->onKernelRequest($getResponseEvent); |
||||
} |
||||
|
||||
function it_returns_null_if_version_is_supported(GetResponseEvent $getResponseEvent, HeaderBag $requestHeaders) |
||||
{ |
||||
$requestHeaders->get('X-Experience-API-Version')->shouldBeCalled()->willReturn('1.0.0'); |
||||
|
||||
$this->onKernelRequest($getResponseEvent)->shouldReturn(null); |
||||
} |
||||
|
||||
function it_sets_a_X_Experience_API_Version_header_in_response(FilterResponseEvent $filterResponseEvent, Response $response, HeaderBag $responseHeaders) |
||||
{ |
||||
$responseHeaders->has('X-Experience-API-Version')->shouldBeCalled()->willReturn(false); |
||||
$responseHeaders->set('X-Experience-API-Version', '1.0.3')->shouldBeCalled(); |
||||
|
||||
$response->headers = $responseHeaders; |
||||
|
||||
$filterResponseEvent->getResponse()->shouldBeCalled()->willReturn($response); |
||||
|
||||
$this->onKernelResponse($filterResponseEvent); |
||||
} |
||||
} |
||||
@ -0,0 +1,159 @@ |
||||
<?php |
||||
|
||||
namespace spec\XApi\LrsBundle\Model; |
||||
|
||||
use PhpSpec\ObjectBehavior; |
||||
use Symfony\Component\HttpFoundation\ParameterBag; |
||||
use Xabbuh\XApi\DataFixtures\ActorFixtures; |
||||
use Xabbuh\XApi\DataFixtures\UuidFixtures; |
||||
use Xabbuh\XApi\Model\StatementsFilter; |
||||
use Xabbuh\XApi\Serializer\ActorSerializerInterface; |
||||
use XApi\Fixtures\Json\ActorJsonFixtures; |
||||
|
||||
class StatementsFilterFactorySpec extends ObjectBehavior |
||||
{ |
||||
function let(ActorSerializerInterface $actorSerializer) |
||||
{ |
||||
$this->beConstructedWith($actorSerializer); |
||||
} |
||||
|
||||
function it_sets_default_filter_when_parameters_are_empty() |
||||
{ |
||||
$filter = $this->createFromParameterBag(new ParameterBag())->getFilter(); |
||||
|
||||
$filter->shouldNotHaveKey('agent'); |
||||
$filter->shouldNotHaveKey('verb'); |
||||
$filter->shouldNotHaveKey('activity'); |
||||
$filter->shouldNotHaveKey('registration'); |
||||
$filter->shouldNotHaveKey('since'); |
||||
$filter->shouldNotHaveKey('until'); |
||||
$filter->shouldHaveKeyWithValue('related_activities', 'false'); |
||||
$filter->shouldHaveKeyWithValue('related_agents', 'false'); |
||||
$filter->shouldHaveKeyWithValue('ascending', 'false'); |
||||
$filter->shouldHaveKeyWithValue('limit', 0); |
||||
} |
||||
|
||||
function it_sets_an_agent_filter(ActorSerializerInterface $actorSerializer) |
||||
{ |
||||
$json = ActorJsonFixtures::getTypicalAgent(); |
||||
$actor = ActorFixtures::getTypicalAgent(); |
||||
|
||||
$actorSerializer->deserializeActor($json)->shouldBeCalled()->willReturn($actor); |
||||
|
||||
$this->beConstructedWith($actorSerializer); |
||||
|
||||
$parameters = new ParameterBag(); |
||||
$parameters->set('agent', $json); |
||||
|
||||
/** @var StatementsFilter $filter */ |
||||
$filter = $this->createFromParameterBag($parameters); |
||||
|
||||
$filter->getFilter()->shouldHaveKeyWithValue('agent', $actor); |
||||
} |
||||
|
||||
function it_sets_a_verb_filter() |
||||
{ |
||||
$verbId = 'http://tincanapi.com/conformancetest/verbid'; |
||||
$parameters = new ParameterBag(); |
||||
$parameters->set('verb', $verbId); |
||||
|
||||
/** @var StatementsFilter $filter */ |
||||
$filter = $this->createFromParameterBag($parameters); |
||||
|
||||
$filter->getFilter()->shouldHaveKeyWithValue('verb', $verbId); |
||||
} |
||||
|
||||
function it_sets_an_activity_filter() |
||||
{ |
||||
$activityId = 'http://tincanapi.com/conformancetest/activityid'; |
||||
$parameters = new ParameterBag(); |
||||
$parameters->set('activity', $activityId); |
||||
|
||||
/** @var StatementsFilter $filter */ |
||||
$filter = $this->createFromParameterBag($parameters); |
||||
|
||||
$filter->getFilter()->shouldHaveKeyWithValue('activity', $activityId); |
||||
} |
||||
|
||||
function it_sets_a_registration_filter() |
||||
{ |
||||
$registration = UuidFixtures::getGoodUuid(); |
||||
$parameters = new ParameterBag(); |
||||
$parameters->set('registration', $registration); |
||||
|
||||
/** @var StatementsFilter $filter */ |
||||
$filter = $this->createFromParameterBag($parameters); |
||||
|
||||
$filter->getFilter()->shouldHaveKeyWithValue('registration', $registration); |
||||
} |
||||
|
||||
function it_sets_a_related_activities_filter() |
||||
{ |
||||
$parameters = new ParameterBag(); |
||||
$parameters->set('related_activities', true); |
||||
|
||||
/** @var StatementsFilter $filter */ |
||||
$filter = $this->createFromParameterBag($parameters); |
||||
|
||||
$filter->getFilter()->shouldHaveKeyWithValue('related_activities', 'true'); |
||||
} |
||||
|
||||
function it_sets_a_related_agents_filter() |
||||
{ |
||||
$parameters = new ParameterBag(); |
||||
$parameters->set('related_agents', true); |
||||
|
||||
/** @var StatementsFilter $filter */ |
||||
$filter = $this->createFromParameterBag($parameters); |
||||
|
||||
$filter->getFilter()->shouldHaveKeyWithValue('related_agents', 'true'); |
||||
} |
||||
|
||||
function it_sets_a_since_filter() |
||||
{ |
||||
$now = new \DateTime(); |
||||
|
||||
$parameters = new ParameterBag(); |
||||
$parameters->set('since', $now->format(\DateTime::ATOM)); |
||||
|
||||
/** @var StatementsFilter $filter */ |
||||
$filter = $this->createFromParameterBag($parameters); |
||||
|
||||
$filter->getFilter()->shouldHaveKeyWithValue('since', $now->format('c')); |
||||
} |
||||
|
||||
function it_sets_an_until_filter() |
||||
{ |
||||
$now = new \DateTime(); |
||||
|
||||
$parameters = new ParameterBag(); |
||||
$parameters->set('until', $now->format(\DateTime::ATOM)); |
||||
|
||||
/** @var StatementsFilter $filter */ |
||||
$filter = $this->createFromParameterBag($parameters); |
||||
|
||||
$filter->getFilter()->shouldHaveKeyWithValue('until', $now->format('c')); |
||||
} |
||||
|
||||
function it_sets_an_ascending_filter() |
||||
{ |
||||
$parameters = new ParameterBag(); |
||||
$parameters->set('ascending', true); |
||||
|
||||
/** @var StatementsFilter $filter */ |
||||
$filter = $this->createFromParameterBag($parameters); |
||||
|
||||
$filter->getFilter()->shouldHaveKeyWithValue('ascending', 'true'); |
||||
} |
||||
|
||||
function it_sets_a_limit_filter() |
||||
{ |
||||
$parameters = new ParameterBag(); |
||||
$parameters->set('limit', 10); |
||||
|
||||
/** @var StatementsFilter $filter */ |
||||
$filter = $this->createFromParameterBag($parameters); |
||||
|
||||
$filter->getFilter()->shouldHaveKeyWithValue('limit', 10); |
||||
} |
||||
} |
||||
@ -0,0 +1,69 @@ |
||||
<?php |
||||
|
||||
namespace spec\XApi\LrsBundle\Response; |
||||
|
||||
use PhpSpec\ObjectBehavior; |
||||
use Symfony\Component\HttpFoundation\Request; |
||||
use Xabbuh\XApi\DataFixtures\AttachmentFixtures; |
||||
use Xabbuh\XApi\Model\Attachment; |
||||
|
||||
class AttachmentResponseSpec extends ObjectBehavior |
||||
{ |
||||
/** |
||||
* @var Attachment |
||||
*/ |
||||
private $attachment; |
||||
|
||||
function let() |
||||
{ |
||||
$this->attachment = AttachmentFixtures::getTextAttachment(); |
||||
|
||||
$this->beConstructedWith($this->attachment); |
||||
} |
||||
|
||||
function it_should_throw_a_logicexception_when_sending_content() |
||||
{ |
||||
$this |
||||
->shouldThrow('\LogicException') |
||||
->during('sendContent'); |
||||
} |
||||
|
||||
function it_should_throw_a_logicexception_when_setting_content() |
||||
{ |
||||
$this |
||||
->shouldThrow('\LogicException') |
||||
->during('setContent', array('a custom content')); |
||||
} |
||||
|
||||
function it_should_return_content_of_the_attachment() |
||||
{ |
||||
$this->getContent()->shouldBe($this->attachment->getContent()); |
||||
} |
||||
|
||||
function it_should_set_Content_Type_header_equals_to_ContentType_property_of_attachment() |
||||
{ |
||||
$request = new Request(); |
||||
|
||||
$this->prepare($request); |
||||
|
||||
$this->headers->get('Content-Type')->shouldBe($this->attachment->getContentType()); |
||||
} |
||||
|
||||
function it_should_set_Content_Transfer_Encoding_header_equals_to_binary() |
||||
{ |
||||
$request = new Request(); |
||||
|
||||
$this->prepare($request); |
||||
|
||||
$this->headers->get('Content-Transfer-Encoding')->shouldBe('binary'); |
||||
} |
||||
|
||||
function it_should_set_X_Experience_API_Hash_header_equals_to_sha2_property_of_attachment() |
||||
{ |
||||
$request = new Request(); |
||||
|
||||
$this->prepare($request); |
||||
|
||||
$this->headers->get('X-Experience-API-Hash')->shouldBe($this->attachment->getSha2()); |
||||
} |
||||
} |
||||
@ -0,0 +1,31 @@ |
||||
<?php |
||||
|
||||
namespace spec\XApi\LrsBundle\Response; |
||||
|
||||
use PhpSpec\ObjectBehavior; |
||||
use Symfony\Component\HttpFoundation\JsonResponse; |
||||
use Symfony\Component\HttpFoundation\Request; |
||||
|
||||
class MultipartResponseSpec extends ObjectBehavior |
||||
{ |
||||
function let(JsonResponse $statementResponse) |
||||
{ |
||||
$this->beConstructedWith($statementResponse); |
||||
} |
||||
|
||||
function it_should_throw_a_logicexception_when_setting_content() |
||||
{ |
||||
$this |
||||
->shouldThrow('\LogicException') |
||||
->during('setContent', array('a custom content')); |
||||
} |
||||
|
||||
function it_should_set_Content_Type_header_of_a_multipart_response() |
||||
{ |
||||
$request = new Request(); |
||||
|
||||
$this->prepare($request); |
||||
|
||||
$this->headers->get('Content-Type')->shouldStartWith('multipart/mixed; boundary='); |
||||
} |
||||
} |
||||
@ -0,0 +1,13 @@ |
||||
<?php |
||||
|
||||
namespace spec\XApi\LrsBundle; |
||||
|
||||
use PhpSpec\ObjectBehavior; |
||||
|
||||
class XApiLrsBundleSpec extends ObjectBehavior |
||||
{ |
||||
function it_is_a_bundle() |
||||
{ |
||||
$this->shouldHaveType('Symfony\Component\HttpKernel\Bundle\Bundle'); |
||||
} |
||||
} |
||||
@ -0,0 +1,194 @@ |
||||
<?php |
||||
|
||||
/* |
||||
* This file is part of the xAPI package. |
||||
* |
||||
* (c) Christian Flothmann <christian.flothmann@xabbuh.de> |
||||
* |
||||
* For the full copyright and license information, please view the LICENSE |
||||
* file that was distributed with this source code. |
||||
*/ |
||||
|
||||
namespace XApi\LrsBundle\Controller; |
||||
|
||||
use Symfony\Component\HttpFoundation\JsonResponse; |
||||
use Symfony\Component\HttpFoundation\ParameterBag; |
||||
use Symfony\Component\HttpFoundation\Request; |
||||
use Symfony\Component\HttpFoundation\Response; |
||||
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException; |
||||
use Xabbuh\XApi\Common\Exception\NotFoundException; |
||||
use Xabbuh\XApi\Model\Statement; |
||||
use Xabbuh\XApi\Model\StatementId; |
||||
use Xabbuh\XApi\Model\StatementResult; |
||||
use Xabbuh\XApi\Serializer\StatementResultSerializerInterface; |
||||
use Xabbuh\XApi\Serializer\StatementSerializerInterface; |
||||
use XApi\LrsBundle\Model\StatementsFilterFactory; |
||||
use XApi\LrsBundle\Response\AttachmentResponse; |
||||
use XApi\LrsBundle\Response\MultipartResponse; |
||||
use XApi\Repository\Api\StatementRepositoryInterface; |
||||
|
||||
/** |
||||
* @author Jérôme Parmentier <jerome.parmentier@acensi.fr> |
||||
*/ |
||||
final class StatementGetController |
||||
{ |
||||
private static $getParameters = array( |
||||
'statementId' => true, |
||||
'voidedStatementId' => true, |
||||
'agent' => true, |
||||
'verb' => true, |
||||
'activity' => true, |
||||
'registration' => true, |
||||
'related_activities' => true, |
||||
'related_agents' => true, |
||||
'since' => true, |
||||
'until' => true, |
||||
'limit' => true, |
||||
'format' => true, |
||||
'attachments' => true, |
||||
'ascending' => true, |
||||
); |
||||
|
||||
private $repository; |
||||
private $statementSerializer; |
||||
private $statementResultSerializer; |
||||
private $statementsFilterFactory; |
||||
|
||||
public function __construct(StatementRepositoryInterface $repository, StatementSerializerInterface $statementSerializer, StatementResultSerializerInterface $statementResultSerializer, StatementsFilterFactory $statementsFilterFactory) |
||||
{ |
||||
$this->repository = $repository; |
||||
$this->statementSerializer = $statementSerializer; |
||||
$this->statementResultSerializer = $statementResultSerializer; |
||||
$this->statementsFilterFactory = $statementsFilterFactory; |
||||
} |
||||
|
||||
/** |
||||
* @param Request $request |
||||
* |
||||
* @throws BadRequestHttpException if the query parameters does not comply with xAPI specification |
||||
* |
||||
* @return Response |
||||
*/ |
||||
public function getStatement(Request $request) |
||||
{ |
||||
$query = new ParameterBag(\array_intersect_key($request->query->all(), self::$getParameters)); |
||||
|
||||
$this->validate($query); |
||||
|
||||
$includeAttachments = $query->filter('attachments', false, FILTER_VALIDATE_BOOLEAN); |
||||
try { |
||||
if (($statementId = $query->get('statementId')) !== null) { |
||||
$statement = $this->repository->findStatementById(StatementId::fromString($statementId)); |
||||
|
||||
$response = $this->buildSingleStatementResponse($statement, $includeAttachments); |
||||
} elseif (($voidedStatementId = $query->get('voidedStatementId')) !== null) { |
||||
$statement = $this->repository->findVoidedStatementById(StatementId::fromString($voidedStatementId)); |
||||
|
||||
$response = $this->buildSingleStatementResponse($statement, $includeAttachments); |
||||
} else { |
||||
$statements = $this->repository->findStatementsBy($this->statementsFilterFactory->createFromParameterBag($query)); |
||||
|
||||
$response = $this->buildMultiStatementsResponse($statements, $includeAttachments); |
||||
} |
||||
} catch (NotFoundException $e) { |
||||
$response = $this->buildMultiStatementsResponse(array()); |
||||
} |
||||
|
||||
$now = new \DateTime(); |
||||
$response->headers->set('X-Experience-API-Consistent-Through', $now->format(\DateTime::ATOM)); |
||||
|
||||
return $response; |
||||
} |
||||
|
||||
/** |
||||
* @param Statement $statement |
||||
* @param bool $includeAttachments true to include the attachments in the response, false otherwise |
||||
* |
||||
* @return JsonResponse|MultipartResponse |
||||
*/ |
||||
protected function buildSingleStatementResponse(Statement $statement, $includeAttachments = false) |
||||
{ |
||||
$json = $this->statementSerializer->serializeStatement($statement); |
||||
|
||||
$response = new JsonResponse($json, 200, array(), true); |
||||
|
||||
if ($includeAttachments) { |
||||
$response = $this->buildMultipartResponse($response, array($statement)); |
||||
} |
||||
|
||||
$response->setLastModified($statement->getStored()); |
||||
|
||||
return $response; |
||||
} |
||||
|
||||
/** |
||||
* @param Statement[] $statements |
||||
* @param bool $includeAttachments true to include the attachments in the response, false otherwise |
||||
* |
||||
* @return JsonResponse|MultipartResponse |
||||
*/ |
||||
protected function buildMultiStatementsResponse(array $statements, $includeAttachments = false) |
||||
{ |
||||
$json = $this->statementResultSerializer->serializeStatementResult(new StatementResult($statements)); |
||||
|
||||
$response = new JsonResponse($json, 200, array(), true); |
||||
|
||||
if ($includeAttachments) { |
||||
$response = $this->buildMultipartResponse($response, $statements); |
||||
} |
||||
|
||||
return $response; |
||||
} |
||||
|
||||
/** |
||||
* @param JsonResponse $statementResponse |
||||
* @param Statement[] $statements |
||||
* |
||||
* @return MultipartResponse |
||||
*/ |
||||
protected function buildMultipartResponse(JsonResponse $statementResponse, array $statements) |
||||
{ |
||||
$attachmentsParts = array(); |
||||
|
||||
foreach ($statements as $statement) { |
||||
foreach ((array) $statement->getAttachments() as $attachment) { |
||||
$attachmentsParts[] = new AttachmentResponse($attachment); |
||||
} |
||||
} |
||||
|
||||
return new MultipartResponse($statementResponse, $attachmentsParts); |
||||
} |
||||
|
||||
/** |
||||
* Validate the parameters. |
||||
* |
||||
* @param ParameterBag $query |
||||
* |
||||
* @throws BadRequestHttpException if the parameters does not comply with the xAPI specification |
||||
*/ |
||||
private function validate(ParameterBag $query) |
||||
{ |
||||
$hasStatementId = $query->has('statementId'); |
||||
$hasVoidedStatementId = $query->has('voidedStatementId'); |
||||
|
||||
if ($hasStatementId && $hasVoidedStatementId) { |
||||
throw new BadRequestHttpException('Request must not have both statementId and voidedStatementId parameters at the same time.'); |
||||
} |
||||
|
||||
$hasAttachments = $query->has('attachments'); |
||||
$hasFormat = $query->has('format'); |
||||
$queryCount = $query->count(); |
||||
|
||||
if (($hasStatementId || $hasVoidedStatementId) && $hasAttachments && $hasFormat && $queryCount > 3) { |
||||
throw new BadRequestHttpException('Request must not contain statementId or voidedStatementId parameters, and also any other parameter besides "attachments" or "format".'); |
||||
} |
||||
|
||||
if (($hasStatementId || $hasVoidedStatementId) && ($hasAttachments || $hasFormat) && $queryCount > 2) { |
||||
throw new BadRequestHttpException('Request must not contain statementId or voidedStatementId parameters, and also any other parameter besides "attachments" or "format".'); |
||||
} |
||||
|
||||
if (($hasStatementId || $hasVoidedStatementId) && $queryCount > 1) { |
||||
throw new BadRequestHttpException('Request must not contain statementId or voidedStatementId parameters, and also any other parameter besides "attachments" or "format".'); |
||||
} |
||||
} |
||||
} |
||||
@ -0,0 +1,33 @@ |
||||
<?php |
||||
|
||||
/* |
||||
* This file is part of the xAPI package. |
||||
* |
||||
* (c) Christian Flothmann <christian.flothmann@xabbuh.de> |
||||
* |
||||
* For the full copyright and license information, please view the LICENSE |
||||
* file that was distributed with this source code. |
||||
*/ |
||||
|
||||
namespace XApi\LrsBundle\Controller; |
||||
|
||||
use Symfony\Component\HttpFoundation\Request; |
||||
use Xabbuh\XApi\Model\Statement; |
||||
|
||||
/** |
||||
* @author Jérôme Parmentier <jerome.parmentier@acensi.fr> |
||||
*/ |
||||
final class StatementPostController |
||||
{ |
||||
public function postStatement(Request $request, Statement $statement) |
||||
{ |
||||
} |
||||
|
||||
/** |
||||
* @param Request $request |
||||
* @param Statement[] $statements |
||||
*/ |
||||
public function postStatements(Request $request, array $statements) |
||||
{ |
||||
} |
||||
} |
||||
@ -0,0 +1,63 @@ |
||||
<?php |
||||
|
||||
/* |
||||
* This file is part of the xAPI package. |
||||
* |
||||
* (c) Christian Flothmann <christian.flothmann@xabbuh.de> |
||||
* |
||||
* For the full copyright and license information, please view the LICENSE |
||||
* file that was distributed with this source code. |
||||
*/ |
||||
|
||||
namespace XApi\LrsBundle\Controller; |
||||
|
||||
use Symfony\Component\HttpFoundation\Request; |
||||
use Symfony\Component\HttpFoundation\Response; |
||||
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException; |
||||
use Symfony\Component\HttpKernel\Exception\ConflictHttpException; |
||||
use Xabbuh\XApi\Common\Exception\NotFoundException; |
||||
use Xabbuh\XApi\Model\Statement; |
||||
use Xabbuh\XApi\Model\StatementId; |
||||
use XApi\Repository\Api\StatementRepositoryInterface; |
||||
|
||||
/** |
||||
* @author Christian Flothmann <christian.flothmann@xabbuh.de> |
||||
*/ |
||||
final class StatementPutController |
||||
{ |
||||
private $repository; |
||||
|
||||
public function __construct(StatementRepositoryInterface $repository) |
||||
{ |
||||
$this->repository = $repository; |
||||
} |
||||
|
||||
public function putStatement(Request $request, Statement $statement) |
||||
{ |
||||
if (null === $statementId = $request->query->get('statementId')) { |
||||
throw new BadRequestHttpException('Required statementId parameter is missing.'); |
||||
} |
||||
|
||||
try { |
||||
$id = StatementId::fromString($statementId); |
||||
} catch (\InvalidArgumentException $e) { |
||||
throw new BadRequestHttpException(sprintf('Parameter statementId ("%s") is not a valid UUID.', $statementId), $e); |
||||
} |
||||
|
||||
if (null !== $statement->getId() && !$id->equals($statement->getId())) { |
||||
throw new ConflictHttpException(sprintf('Id parameter ("%s") and statement id ("%s") do not match.', $id->getValue(), $statement->getId()->getValue())); |
||||
} |
||||
|
||||
try { |
||||
$existingStatement = $this->repository->findStatementById($id); |
||||
|
||||
if (!$existingStatement->equals($statement)) { |
||||
throw new ConflictHttpException('The new statement is not equal to an existing statement with the same id.'); |
||||
} |
||||
} catch (NotFoundException $e) { |
||||
$this->repository->storeStatement($statement, true); |
||||
} |
||||
|
||||
return new Response('', 204); |
||||
} |
||||
} |
||||
@ -0,0 +1,35 @@ |
||||
<?php |
||||
|
||||
namespace XApi\LrsBundle\DependencyInjection; |
||||
|
||||
use Symfony\Component\Config\Definition\Builder\TreeBuilder; |
||||
use Symfony\Component\Config\Definition\ConfigurationInterface; |
||||
|
||||
/** |
||||
* @author Christian Flothmann <christian.flothmann@xabbuh.de> |
||||
*/ |
||||
final class Configuration implements ConfigurationInterface |
||||
{ |
||||
public function getConfigTreeBuilder() |
||||
{ |
||||
$treeBuilder = new TreeBuilder(); |
||||
|
||||
$treeBuilder |
||||
->root('xapi_lrs') |
||||
->beforeNormalization() |
||||
->ifTrue(function ($v) { return isset($v['type']) && in_array($v['type'], array('mongodb', 'orm')) && !isset($v['object_manager_service']); }) |
||||
->thenInvalid('You need to configure the object manager service when the repository type is "mongodb" or orm".') |
||||
->end() |
||||
->children() |
||||
->enumNode('type') |
||||
->isRequired() |
||||
->values(array('in_memory', 'mongodb', 'orm')) |
||||
->end() |
||||
->scalarNode('object_manager_service')->end() |
||||
->end() |
||||
->end() |
||||
; |
||||
|
||||
return $treeBuilder; |
||||
} |
||||
} |
||||
@ -0,0 +1,60 @@ |
||||
<?php |
||||
|
||||
/* |
||||
* This file is part of the xAPI package. |
||||
* |
||||
* (c) Christian Flothmann <christian.flothmann@xabbuh.de> |
||||
* |
||||
* For the full copyright and license information, please view the LICENSE |
||||
* file that was distributed with this source code. |
||||
*/ |
||||
|
||||
namespace XApi\LrsBundle\DependencyInjection; |
||||
|
||||
use Symfony\Component\Config\FileLocator; |
||||
use Symfony\Component\DependencyInjection\ContainerBuilder; |
||||
use Symfony\Component\DependencyInjection\Extension\Extension; |
||||
use Symfony\Component\DependencyInjection\Loader\XmlFileLoader; |
||||
|
||||
/** |
||||
* @author Christian Flothmann <christian.flothmann@xabbuh.de> |
||||
*/ |
||||
final class XApiLrsExtension extends Extension |
||||
{ |
||||
public function load(array $configs, ContainerBuilder $container) |
||||
{ |
||||
$configuration = new Configuration(); |
||||
$config = $this->processConfiguration($configuration, $configs); |
||||
|
||||
$loader = new XmlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config')); |
||||
|
||||
$loader->load('controller.xml'); |
||||
$loader->load('event_listener.xml'); |
||||
$loader->load('factory.xml'); |
||||
$loader->load('serializer.xml'); |
||||
|
||||
switch ($config['type']) { |
||||
case 'in_memory': |
||||
break; |
||||
case 'mongodb': |
||||
$loader->load('doctrine.xml'); |
||||
$loader->load('mongodb.xml'); |
||||
|
||||
$container->setAlias('xapi_lrs.doctrine.object_manager', $config['object_manager_service']); |
||||
$container->setAlias('xapi_lrs.repository.statement', 'xapi_lrs.repository.statement.doctrine'); |
||||
break; |
||||
case 'orm': |
||||
$loader->load('doctrine.xml'); |
||||
$loader->load('orm.xml'); |
||||
|
||||
$container->setAlias('xapi_lrs.doctrine.object_manager', $config['object_manager_service']); |
||||
$container->setAlias('xapi_lrs.repository.statement', 'xapi_lrs.repository.statement.doctrine'); |
||||
break; |
||||
} |
||||
} |
||||
|
||||
public function getAlias() |
||||
{ |
||||
return 'xapi_lrs'; |
||||
} |
||||
} |
||||
@ -0,0 +1,73 @@ |
||||
<?php |
||||
|
||||
/* |
||||
* This file is part of the xAPI package. |
||||
* |
||||
* (c) Christian Flothmann <christian.flothmann@xabbuh.de> |
||||
* |
||||
* For the full copyright and license information, please view the LICENSE |
||||
* file that was distributed with this source code. |
||||
*/ |
||||
|
||||
namespace XApi\LrsBundle\EventListener; |
||||
|
||||
use Symfony\Component\HttpKernel\Event\GetResponseEvent; |
||||
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException; |
||||
|
||||
/** |
||||
* @author Jérôme Parmentier <jerome.parmentier@acensi.fr> |
||||
*/ |
||||
class AlternateRequestSyntaxListener |
||||
{ |
||||
public function onKernelRequest(GetResponseEvent $event) |
||||
{ |
||||
if (!$event->isMasterRequest()) { |
||||
return; |
||||
} |
||||
|
||||
$request = $event->getRequest(); |
||||
|
||||
if (!$request->attributes->has('xapi_lrs.route')) { |
||||
return; |
||||
} |
||||
|
||||
if ('POST' !== $request->getMethod()) { |
||||
return; |
||||
} |
||||
|
||||
if (null === $method = $request->query->get('method')) { |
||||
return; |
||||
} |
||||
|
||||
if ($request->query->count() > 1) { |
||||
throw new BadRequestHttpException('Including other query parameters than "method" is not allowed. You have to send them as POST parameters inside the request body.'); |
||||
} |
||||
|
||||
$request->setMethod($method); |
||||
$request->query->remove('method'); |
||||
|
||||
if (null !== $content = $request->request->get('content')) { |
||||
$request->request->remove('content'); |
||||
|
||||
$request->initialize( |
||||
$request->query->all(), |
||||
$request->request->all(), |
||||
$request->attributes->all(), |
||||
$request->cookies->all(), |
||||
$request->files->all(), |
||||
$request->server->all(), |
||||
$content |
||||
); |
||||
} |
||||
|
||||
foreach ($request->request as $key => $value) { |
||||
if (in_array($key, array('Authorization', 'X-Experience-API-Version', 'Content-Type', 'Content-Length', 'If-Match', 'If-None-Match'), true)) { |
||||
$request->headers->set($key, $value); |
||||
} else { |
||||
$request->query->set($key, $value); |
||||
} |
||||
|
||||
$request->request->remove($key); |
||||
} |
||||
} |
||||
} |
||||
@ -0,0 +1,17 @@ |
||||
<?php |
||||
|
||||
namespace XApi\LrsBundle\EventListener; |
||||
|
||||
use Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent; |
||||
|
||||
/** |
||||
* Converts Experience API specific domain exceptions into proper HTTP responses. |
||||
* |
||||
* @author Christian Flothmann <christian.flothmann@xabbuh.de> |
||||
*/ |
||||
class ExceptionListener |
||||
{ |
||||
public function onKernelException(GetResponseForExceptionEvent $event) |
||||
{ |
||||
} |
||||
} |
||||
@ -0,0 +1,40 @@ |
||||
<?php |
||||
|
||||
namespace XApi\LrsBundle\EventListener; |
||||
|
||||
use Symfony\Component\HttpKernel\Event\GetResponseEvent; |
||||
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException; |
||||
use Symfony\Component\Serializer\Exception\ExceptionInterface as BaseSerializerException; |
||||
use Xabbuh\XApi\Serializer\StatementSerializerInterface; |
||||
|
||||
/** |
||||
* @author Christian Flothmann <christian.flothmann@xabbuh.de> |
||||
*/ |
||||
class SerializerListener |
||||
{ |
||||
private $statementSerializer; |
||||
|
||||
public function __construct(StatementSerializerInterface $statementSerializer) |
||||
{ |
||||
$this->statementSerializer = $statementSerializer; |
||||
} |
||||
|
||||
public function onKernelRequest(GetResponseEvent $event) |
||||
{ |
||||
$request = $event->getRequest(); |
||||
|
||||
if (!$request->attributes->has('xapi_lrs.route')) { |
||||
return; |
||||
} |
||||
|
||||
try { |
||||
switch ($request->attributes->get('xapi_serializer')) { |
||||
case 'statement': |
||||
$request->attributes->set('statement', $this->statementSerializer->deserializeStatement($request->getContent())); |
||||
break; |
||||
} |
||||
} catch (BaseSerializerException $e) { |
||||
throw new BadRequestHttpException(sprintf('The content of the request cannot be deserialized into a valid xAPI %s.', $request->attributes->get('xapi_serializer')), $e); |
||||
} |
||||
} |
||||
} |
||||
@ -0,0 +1,66 @@ |
||||
<?php |
||||
|
||||
/* |
||||
* This file is part of the xAPI package. |
||||
* |
||||
* (c) Christian Flothmann <christian.flothmann@xabbuh.de> |
||||
* |
||||
* For the full copyright and license information, please view the LICENSE |
||||
* file that was distributed with this source code. |
||||
*/ |
||||
|
||||
namespace XApi\LrsBundle\EventListener; |
||||
|
||||
use Symfony\Component\HttpKernel\Event\FilterResponseEvent; |
||||
use Symfony\Component\HttpKernel\Event\GetResponseEvent; |
||||
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException; |
||||
|
||||
/** |
||||
* @author Jérôme Parmentier <jerome.parmentier@acensi.fr> |
||||
*/ |
||||
class VersionListener |
||||
{ |
||||
public function onKernelRequest(GetResponseEvent $event) |
||||
{ |
||||
if (!$event->isMasterRequest()) { |
||||
return; |
||||
} |
||||
|
||||
$request = $event->getRequest(); |
||||
|
||||
if (!$request->attributes->has('xapi_lrs.route')) { |
||||
return; |
||||
} |
||||
|
||||
if (null === $version = $request->headers->get('X-Experience-API-Version')) { |
||||
throw new BadRequestHttpException('Missing required "X-Experience-API-Version" header.'); |
||||
} |
||||
|
||||
if (preg_match('/^1\.0(?:\.\d+)?$/', $version)) { |
||||
if ('1.0' === $version) { |
||||
$request->headers->set('X-Experience-API-Version', '1.0.0'); |
||||
} |
||||
|
||||
return; |
||||
} |
||||
|
||||
throw new BadRequestHttpException(sprintf('xAPI version "%s" is not supported.', $version)); |
||||
} |
||||
|
||||
public function onKernelResponse(FilterResponseEvent $event) |
||||
{ |
||||
if (!$event->isMasterRequest()) { |
||||
return; |
||||
} |
||||
|
||||
if (!$event->getRequest()->attributes->has('xapi_lrs.route')) { |
||||
return; |
||||
} |
||||
|
||||
$headers = $event->getResponse()->headers; |
||||
|
||||
if (!$headers->has('X-Experience-API-Version')) { |
||||
$headers->set('X-Experience-API-Version', '1.0.3'); |
||||
} |
||||
} |
||||
} |
||||
@ -0,0 +1,88 @@ |
||||
<?php |
||||
|
||||
/* |
||||
* This file is part of the xAPI package. |
||||
* |
||||
* (c) Christian Flothmann <christian.flothmann@xabbuh.de> |
||||
* |
||||
* For the full copyright and license information, please view the LICENSE |
||||
* file that was distributed with this source code. |
||||
*/ |
||||
|
||||
namespace XApi\LrsBundle\Model; |
||||
|
||||
use Symfony\Component\HttpFoundation\ParameterBag; |
||||
use Xabbuh\XApi\Model\Activity; |
||||
use Xabbuh\XApi\Model\IRI; |
||||
use Xabbuh\XApi\Model\StatementsFilter; |
||||
use Xabbuh\XApi\Model\Verb; |
||||
use Xabbuh\XApi\Serializer\ActorSerializerInterface; |
||||
|
||||
/** |
||||
* @author Jérôme Parmentier <jerome.parmentier@acensi.fr> |
||||
*/ |
||||
class StatementsFilterFactory |
||||
{ |
||||
private $actorSerializer; |
||||
|
||||
public function __construct(ActorSerializerInterface $actorSerializer) |
||||
{ |
||||
$this->actorSerializer = $actorSerializer; |
||||
} |
||||
|
||||
/** |
||||
* @param ParameterBag $parameters |
||||
* |
||||
* @return StatementsFilter |
||||
*/ |
||||
public function createFromParameterBag(ParameterBag $parameters) |
||||
{ |
||||
$filter = new StatementsFilter(); |
||||
|
||||
if (($actor = $parameters->get('agent')) !== null) { |
||||
$filter->byActor($this->actorSerializer->deserializeActor($actor)); |
||||
} |
||||
|
||||
if (($verbId = $parameters->get('verb')) !== null) { |
||||
$filter->byVerb(new Verb(IRI::fromString($verbId))); |
||||
} |
||||
|
||||
if (($activityId = $parameters->get('activity')) !== null) { |
||||
$filter->byActivity(new Activity(IRI::fromString($activityId))); |
||||
} |
||||
|
||||
if (($registration = $parameters->get('registration')) !== null) { |
||||
$filter->byRegistration($registration); |
||||
} |
||||
|
||||
if ($parameters->filter('related_activities', false, FILTER_VALIDATE_BOOLEAN)) { |
||||
$filter->enableRelatedActivityFilter(); |
||||
} else { |
||||
$filter->disableRelatedActivityFilter(); |
||||
} |
||||
|
||||
if ($parameters->filter('related_agents', false, FILTER_VALIDATE_BOOLEAN)) { |
||||
$filter->enableRelatedAgentFilter(); |
||||
} else { |
||||
$filter->disableRelatedAgentFilter(); |
||||
} |
||||
|
||||
if (($since = $parameters->get('since')) !== null) { |
||||
$filter->since(\DateTime::createFromFormat(\DateTime::ATOM, $since)); |
||||
} |
||||
|
||||
if (($until = $parameters->get('until')) !== null) { |
||||
$filter->until(\DateTime::createFromFormat(\DateTime::ATOM, $until)); |
||||
} |
||||
|
||||
if ($parameters->filter('ascending', false, FILTER_VALIDATE_BOOLEAN)) { |
||||
$filter->ascending(); |
||||
} else { |
||||
$filter->descending(); |
||||
} |
||||
|
||||
$filter->limit($parameters->getInt('limit')); |
||||
|
||||
return $filter; |
||||
} |
||||
} |
||||
@ -0,0 +1,21 @@ |
||||
<?xml version="1.0" encoding="UTF-8" ?> |
||||
<container xmlns="http://symfony.com/schema/dic/services" |
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |
||||
xsi:schemaLocation="http://symfony.com/schema/dic/services |
||||
http://symfony.com/schema/dic/services/services-1.0.xsd"> |
||||
|
||||
<services> |
||||
<service id="xapi_lrs.controller.statement.get" class="XApi\LrsBundle\Controller\StatementGetController"> |
||||
<argument type="service" id="xapi_lrs.repository.statement"/> |
||||
<argument type="service" id="xapi_lrs.statement.serializer"/> |
||||
<argument type="service" id="xapi_lrs.statement_result.serializer"/> |
||||
<argument type="service" id="xapi_lrs.factory.statements_filter"/> |
||||
</service> |
||||
|
||||
<service id="xapi_lrs.controller.statement.post" class="XApi\LrsBundle\Controller\StatementPostController"/> |
||||
|
||||
<service id="xapi_lrs.controller.statement.put" class="XApi\LrsBundle\Controller\StatementPutController"> |
||||
<argument type="service" id="xapi_lrs.repository.statement"/> |
||||
</service> |
||||
</services> |
||||
</container> |
||||
@ -0,0 +1,12 @@ |
||||
<?xml version="1.0" encoding="UTF-8" ?> |
||||
<container xmlns="http://symfony.com/schema/dic/services" |
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |
||||
xsi:schemaLocation="http://symfony.com/schema/dic/services |
||||
http://symfony.com/schema/dic/services/services-1.0.xsd"> |
||||
|
||||
<services> |
||||
<service id="xapi_lrs.repository.statement.doctrine" class="XApi\Repository\Doctrine\Repository\StatementRepository" public="false"> |
||||
<argument type="service" id="xapi_lrs.repository.mapped_statement" /> |
||||
</service> |
||||
</services> |
||||
</container> |
||||
@ -0,0 +1,25 @@ |
||||
<?xml version="1.0" encoding="UTF-8" ?> |
||||
<container xmlns="http://symfony.com/schema/dic/services" |
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |
||||
xsi:schemaLocation="http://symfony.com/schema/dic/services |
||||
http://symfony.com/schema/dic/services/services-1.0.xsd"> |
||||
|
||||
<services> |
||||
<service id="xapi_lrs.event_listener.alternate_request_syntax" class="XApi\LrsBundle\EventListener\AlternateRequestSyntaxListener"> |
||||
<tag name="kernel.event_listener" event="kernel.request" /> |
||||
</service> |
||||
|
||||
<service id="xapi_lrs.event_listener.exception" class="XApi\LrsBundle\EventListener\ExceptionListener"> |
||||
</service> |
||||
|
||||
<service id="xapi_lrs.event_listener.serializer" class="XApi\LrsBundle\EventListener\SerializerListener"> |
||||
<argument type="service" id="xapi_lrs.statement.serializer" /> |
||||
<tag name="kernel.event_listener" event="kernel.request" /> |
||||
</service> |
||||
|
||||
<service id="xapi_lrs.event_listener.version" class="XApi\LrsBundle\EventListener\VersionListener"> |
||||
<tag name="kernel.event_listener" event="kernel.request" /> |
||||
<tag name="kernel.event_listener" event="kernel.response" /> |
||||
</service> |
||||
</services> |
||||
</container> |
||||
@ -0,0 +1,12 @@ |
||||
<?xml version="1.0" encoding="UTF-8" ?> |
||||
<container xmlns="http://symfony.com/schema/dic/services" |
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |
||||
xsi:schemaLocation="http://symfony.com/schema/dic/services |
||||
http://symfony.com/schema/dic/services/services-1.0.xsd"> |
||||
|
||||
<services> |
||||
<service id="xapi_lrs.factory.statements_filter" class="XApi\LrsBundle\Model\StatementsFilterFactory"> |
||||
<argument type="service" id="xapi_lrs.actor.serializer"/> |
||||
</service> |
||||
</services> |
||||
</container> |
||||
@ -0,0 +1,18 @@ |
||||
<?xml version="1.0" encoding="UTF-8" ?> |
||||
<container xmlns="http://symfony.com/schema/dic/services" |
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |
||||
xsi:schemaLocation="http://symfony.com/schema/dic/services |
||||
http://symfony.com/schema/dic/services/services-1.0.xsd"> |
||||
|
||||
<services> |
||||
<service id="xapi_lrs.doctrine.class_metadata" class="Doctrine\ORM\Mapping\ClassMetadata" public="false"> |
||||
<argument>XApi\Repository\Api\Mapping\MappedStatement</argument> |
||||
<factory service="xapi_lrs.doctrine.object_manager" method="getClassMetadata" /> |
||||
</service> |
||||
|
||||
<service id="xapi_lrs.repository.mapped_statement" class="XApi\Repository\ORM\MappedStatementRepository" public="false"> |
||||
<argument type="service" id="xapi_lrs.doctrine.object_manager" /> |
||||
<argument type="service" id="xapi_lrs.doctrine.class_metadata" /> |
||||
</service> |
||||
</services> |
||||
</container> |
||||
@ -0,0 +1,29 @@ |
||||
<?xml version="1.0" encoding="UTF-8" ?> |
||||
<routes xmlns="http://symfony.com/schema/routing" |
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |
||||
xsi:schemaLocation="http://symfony.com/schema/routing |
||||
http://symfony.com/schema/routing/routing-1.0.xsd"> |
||||
|
||||
<route id="xapi_lrs.statement.put" path="/statements" methods="PUT"> |
||||
<default key="_controller">xapi_lrs.controller.statement.put:putStatement</default> |
||||
<default key="xapi_serializer">statement</default> |
||||
<default key="xapi_lrs.route"> |
||||
<bool>true</bool> |
||||
</default> |
||||
</route> |
||||
|
||||
<route id="xapi_lrs.statement.post" path="/statements" methods="POST"> |
||||
<default key="_controller">xapi_lrs.controller.statement.post:postStatement</default> |
||||
<default key="xapi_serializer">statement</default> |
||||
<default key="xapi_lrs.route"> |
||||
<bool>true</bool> |
||||
</default> |
||||
</route> |
||||
|
||||
<route id="xapi_lrs.statement.get" path="/statements" methods="GET"> |
||||
<default key="_controller">xapi_lrs.controller.statement.get:getStatement</default> |
||||
<default key="xapi_lrs.route"> |
||||
<bool>true</bool> |
||||
</default> |
||||
</route> |
||||
</routes> |
||||
@ -0,0 +1,32 @@ |
||||
<?xml version="1.0" encoding="UTF-8" ?> |
||||
<container xmlns="http://symfony.com/schema/dic/services" |
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |
||||
xsi:schemaLocation="http://symfony.com/schema/dic/services |
||||
http://symfony.com/schema/dic/services/services-1.0.xsd"> |
||||
|
||||
<services> |
||||
<service id="xapi_lrs.statement.serializer" class="Xabbuh\XApi\Serializer\StatementSerializerInterface" public="false"> |
||||
<factory service="xapi_lrs.serializer.factory" method="createStatementSerializer"/> |
||||
</service> |
||||
|
||||
<service id="xapi_lrs.statement_result.serializer" class="Xabbuh\XApi\Serializer\StatementResultSerializerInterface" public="false"> |
||||
<factory service="xapi_lrs.serializer.factory" method="createStatementResultSerializer"/> |
||||
</service> |
||||
|
||||
<service id="xapi_lrs.actor.serializer" class="Xabbuh\XApi\Serializer\ActorSerializerInterface" public="false"> |
||||
<factory service="xapi_lrs.serializer.factory" method="createActorSerializer"/> |
||||
</service> |
||||
|
||||
<service id="xapi_lrs.document_data.serializer" class="Xabbuh\XApi\Serializer\DocumentDataSerializerInterface" public="false"> |
||||
<factory service="xapi_lrs.serializer.factory" method="createDocumentDataSerializer"/> |
||||
</service> |
||||
|
||||
<service id="xapi_lrs.serializer_factory" class="Xabbuh\XApi\Serializer\Symfony\SerializerFactory" public="false"> |
||||
<argument type="service" id="xapi_lrs.serializer"/> |
||||
</service> |
||||
|
||||
<service id="xapi_lrs.serializer" class="Symfony\Component\Serializer\SerializerInterface" public="false"> |
||||
<factory class="Xabbuh\XApi\Serializer\Symfony\Serializer" method="createSerializer"/> |
||||
</service> |
||||
</services> |
||||
</container> |
||||
@ -0,0 +1,79 @@ |
||||
<?php |
||||
|
||||
/* |
||||
* This file is part of the xAPI package. |
||||
* |
||||
* (c) Christian Flothmann <christian.flothmann@xabbuh.de> |
||||
* |
||||
* For the full copyright and license information, please view the LICENSE |
||||
* file that was distributed with this source code. |
||||
*/ |
||||
|
||||
namespace XApi\LrsBundle\Response; |
||||
|
||||
use Symfony\Component\HttpFoundation\Request; |
||||
use Symfony\Component\HttpFoundation\Response; |
||||
use Xabbuh\XApi\Model\Attachment; |
||||
|
||||
/** |
||||
* @author Jérôme Parmentier <jerome.parmentier@acensi.fr> |
||||
*/ |
||||
class AttachmentResponse extends Response |
||||
{ |
||||
protected $attachment; |
||||
|
||||
/** |
||||
* @param Attachment $attachment |
||||
*/ |
||||
public function __construct(Attachment $attachment) |
||||
{ |
||||
parent::__construct(null); |
||||
|
||||
$this->attachment = $attachment; |
||||
} |
||||
|
||||
/** |
||||
* {@inheritdoc} |
||||
*/ |
||||
public function prepare(Request $request) |
||||
{ |
||||
if (!$this->headers->has('Content-Type')) { |
||||
$this->headers->set('Content-Type', $this->attachment->getContentType()); |
||||
} |
||||
|
||||
$this->headers->set('Content-Transfer-Encoding', 'binary'); |
||||
$this->headers->set('X-Experience-API-Hash', $this->attachment->getSha2()); |
||||
} |
||||
|
||||
/** |
||||
* {@inheritdoc} |
||||
* |
||||
* @throws \LogicException |
||||
*/ |
||||
public function sendContent() |
||||
{ |
||||
throw new \LogicException('An AttachmentResponse is only meant to be part of a multipart Response.'); |
||||
} |
||||
|
||||
/** |
||||
* {@inheritdoc} |
||||
* |
||||
* @throws \LogicException when the content is not null |
||||
*/ |
||||
public function setContent($content) |
||||
{ |
||||
if (null !== $content) { |
||||
throw new \LogicException('The content cannot be set on an AttachmentResponse instance.'); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* {@inheritdoc} |
||||
* |
||||
* @return null|string |
||||
*/ |
||||
public function getContent() |
||||
{ |
||||
return $this->attachment->getContent(); |
||||
} |
||||
} |
||||
@ -0,0 +1,139 @@ |
||||
<?php |
||||
|
||||
/* |
||||
* This file is part of the xAPI package. |
||||
* |
||||
* (c) Christian Flothmann <christian.flothmann@xabbuh.de> |
||||
* |
||||
* For the full copyright and license information, please view the LICENSE |
||||
* file that was distributed with this source code. |
||||
*/ |
||||
|
||||
namespace XApi\LrsBundle\Response; |
||||
|
||||
use Symfony\Component\HttpFoundation\JsonResponse; |
||||
use Symfony\Component\HttpFoundation\Request; |
||||
use Symfony\Component\HttpFoundation\Response; |
||||
|
||||
/** |
||||
* @author Jérôme Parmentier <jerome.parmentier@acensi.fr> |
||||
*/ |
||||
class MultipartResponse extends Response |
||||
{ |
||||
protected $subtype; |
||||
protected $boundary; |
||||
protected $statementPart; |
||||
/** |
||||
* @var Response[] |
||||
*/ |
||||
protected $parts; |
||||
|
||||
/** |
||||
* @param JsonResponse $statementPart |
||||
* @param AttachmentResponse[] $attachmentsParts |
||||
* @param int $status |
||||
* @param array $headers |
||||
* @param null|string $subtype |
||||
*/ |
||||
public function __construct(JsonResponse $statementPart, array $attachmentsParts = array(), $status = 200, array $headers = array(), $subtype = null) |
||||
{ |
||||
parent::__construct(null, $status, $headers); |
||||
|
||||
if (null === $subtype) { |
||||
$subtype = 'mixed'; |
||||
} |
||||
|
||||
$this->subtype = $subtype; |
||||
$this->boundary = uniqid('', true); |
||||
$this->statementPart = $statementPart; |
||||
|
||||
$this->setAttachmentsParts($attachmentsParts); |
||||
} |
||||
|
||||
/** |
||||
* @param AttachmentResponse $part |
||||
* |
||||
* @return $this |
||||
*/ |
||||
public function addAttachmentPart(AttachmentResponse $part) |
||||
{ |
||||
if ($part->getContent() !== null) { |
||||
$this->parts[] = $part; |
||||
} |
||||
|
||||
return $this; |
||||
} |
||||
|
||||
/** |
||||
* @param AttachmentResponse[] $attachmentsParts |
||||
* |
||||
* @return $this |
||||
*/ |
||||
public function setAttachmentsParts(array $attachmentsParts) |
||||
{ |
||||
$this->parts = array($this->statementPart); |
||||
|
||||
foreach ($attachmentsParts as $part) { |
||||
$this->addAttachmentPart($part); |
||||
} |
||||
|
||||
return $this; |
||||
} |
||||
|
||||
/** |
||||
* {@inheritdoc} |
||||
*/ |
||||
public function prepare(Request $request) |
||||
{ |
||||
foreach ($this->parts as $part) { |
||||
$part->prepare($request); |
||||
} |
||||
|
||||
$this->headers->set('Content-Type', sprintf('multipart/%s; boundary="%s"', $this->subtype, $this->boundary)); |
||||
$this->headers->set('Transfer-Encoding', 'chunked'); |
||||
|
||||
return parent::prepare($request); |
||||
} |
||||
|
||||
/** |
||||
* {@inheritdoc} |
||||
*/ |
||||
public function sendContent() |
||||
{ |
||||
$content = ''; |
||||
foreach ($this->parts as $part) { |
||||
$content .= sprintf('--%s', $this->boundary)."\r\n"; |
||||
$content .= $part->headers."\r\n"; |
||||
$content .= $part->getContent(); |
||||
$content .= "\r\n"; |
||||
} |
||||
|
||||
$content .= sprintf('--%s--', $this->boundary)."\r\n"; |
||||
|
||||
echo $content; |
||||
|
||||
return $this; |
||||
} |
||||
|
||||
/** |
||||
* {@inheritdoc} |
||||
* |
||||
* @throws \LogicException when the content is not null |
||||
*/ |
||||
public function setContent($content) |
||||
{ |
||||
if (null !== $content) { |
||||
throw new \LogicException('The content cannot be set on a MultipartResponse instance.'); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* {@inheritdoc} |
||||
* |
||||
* @return false |
||||
*/ |
||||
public function getContent() |
||||
{ |
||||
return false; |
||||
} |
||||
} |
||||
@ -0,0 +1,26 @@ |
||||
<?php |
||||
|
||||
/* |
||||
* This file is part of the xAPI package. |
||||
* |
||||
* (c) Christian Flothmann <christian.flothmann@xabbuh.de> |
||||
* |
||||
* For the full copyright and license information, please view the LICENSE |
||||
* file that was distributed with this source code. |
||||
*/ |
||||
|
||||
namespace XApi\LrsBundle; |
||||
|
||||
use Symfony\Component\HttpKernel\Bundle\Bundle; |
||||
use XApi\LrsBundle\DependencyInjection\XApiLrsExtension; |
||||
|
||||
/** |
||||
* @author Christian Flothmann <christian.flothmann@xabbuh.de> |
||||
*/ |
||||
class XApiLrsBundle extends Bundle |
||||
{ |
||||
public function getContainerExtension() |
||||
{ |
||||
return new XApiLrsExtension(); |
||||
} |
||||
} |
||||
@ -0,0 +1,19 @@ |
||||
Copyright (c) 2016-2017 Christian Flothmann |
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy |
||||
of this software and associated documentation files (the "Software"), to deal |
||||
in the Software without restriction, including without limitation the rights |
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
||||
copies of the Software, and to permit persons to whom the Software is furnished |
||||
to do so, subject to the following conditions: |
||||
|
||||
The above copyright notice and this permission notice shall be included in all |
||||
copies or substantial portions of the Software. |
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
||||
THE SOFTWARE. |
||||
@ -0,0 +1,41 @@ |
||||
{ |
||||
"name": "php-xapi/repository-doctrine-orm", |
||||
"description": "Doctrine based ORM implementations of an Experience API (xAPI) repository", |
||||
"keywords": ["xAPI", "Tin Can API", "Experience API", "storage", "database", "repository", "entity", "Doctrine", "ORM"], |
||||
"homepage": "https://github.com/php-xapi/repository-orm/", |
||||
"license": "MIT", |
||||
"authors": [ |
||||
{ |
||||
"name": "Christian Flothmann", |
||||
"homepage": "https://github.com/xabbuh" |
||||
} |
||||
], |
||||
"require": { |
||||
"php": "^5.6 || ^7.0", |
||||
"doctrine/orm": "^2.3", |
||||
"php-xapi/repository-api": "^0.4", |
||||
"php-xapi/repository-doctrine": "^0.4" |
||||
}, |
||||
"require-dev": { |
||||
"symfony/phpunit-bridge": "^3.4 || ^4.0" |
||||
}, |
||||
"provide": { |
||||
"php-xapi/repository-implementation": "0.3" |
||||
}, |
||||
"autoload": { |
||||
"psr-4": { |
||||
"XApi\\Repository\\ORM\\": "src/" |
||||
} |
||||
}, |
||||
"autoload-dev": { |
||||
"psr-4": { |
||||
"XApi\\Repository\\ORM\\Tests\\": "tests/" |
||||
} |
||||
}, |
||||
"minimum-stability": "dev", |
||||
"extra": { |
||||
"branch-alias": { |
||||
"dev-master": "0.1.x-dev" |
||||
} |
||||
} |
||||
} |
||||
@ -0,0 +1,19 @@ |
||||
<doctrine-mapping xmlns="http://doctrine-project.org/schemas/orm/doctrine-mapping" |
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |
||||
xsi:schemaLocation="http://doctrine-project.org/schemas/orm/doctrine-mapping |
||||
http://doctrine-project.org/schemas/orm/doctrine-mapping.xsd"> |
||||
|
||||
<entity name="XApi\Repository\Doctrine\Mapping\Actor" table="xapi_actor"> |
||||
<id name="identifier" type="integer"> |
||||
<generator strategy="AUTO" /> |
||||
</id> |
||||
|
||||
<field name="type" type="string" nullable="true" /> |
||||
<field name="mbox" type="string" nullable="true" /> |
||||
<field name="mboxSha1Sum" type="string" nullable="true" /> |
||||
<field name="openId" type="string" nullable="true" /> |
||||
<field name="accountName" type="string" nullable="true" /> |
||||
<field name="accountHomePage" type="string" nullable="true" /> |
||||
<field name="name" type="string" nullable="true" /> |
||||
</entity> |
||||
</doctrine-mapping> |
||||
@ -0,0 +1,23 @@ |
||||
<doctrine-mapping xmlns="http://doctrine-project.org/schemas/orm/doctrine-mapping" |
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |
||||
xsi:schemaLocation="http://doctrine-project.org/schemas/orm/doctrine-mapping |
||||
http://doctrine-project.org/schemas/orm/doctrine-mapping.xsd"> |
||||
|
||||
<entity name="XApi\Repository\Doctrine\Mapping\Attachment" table="xapi_attachment"> |
||||
<id name="identifier" type="integer"> |
||||
<generator strategy="AUTO" /> |
||||
</id> |
||||
|
||||
<field name="usageType" type="string" /> |
||||
<field name="contentType" type="string" /> |
||||
<field name="length" type="integer" /> |
||||
<field name="sha2" type="string" /> |
||||
<field name="display" type="json_array" /> |
||||
<field name="hasDescription" type="boolean" /> |
||||
<field name="description" type="json_array" nullable="true" /> |
||||
<field name="fileUrl" type="string" nullable="true" /> |
||||
<field name="content" type="text" nullable="true" /> |
||||
|
||||
<many-to-one field="statement" target-entity="XApi\Repository\Doctrine\Mapping\Statement" inversed-by="attachments" /> |
||||
</entity> |
||||
</doctrine-mapping> |
||||
@ -0,0 +1,59 @@ |
||||
<doctrine-mapping xmlns="http://doctrine-project.org/schemas/orm/doctrine-mapping" |
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |
||||
xsi:schemaLocation="http://doctrine-project.org/schemas/orm/doctrine-mapping |
||||
http://doctrine-project.org/schemas/orm/doctrine-mapping.xsd"> |
||||
|
||||
<entity name="XApi\Repository\Doctrine\Mapping\Context" table="xapi_context"> |
||||
<id name="identifier" type="integer"> |
||||
<generator strategy="AUTO" /> |
||||
</id> |
||||
|
||||
<field name="registration" type="string" nullable="true" /> |
||||
<field name="hasContextActivities" type="boolean" nullable="true" /> |
||||
<field name="revision" type="string" nullable="true" /> |
||||
<field name="platform" type="string" nullable="true" /> |
||||
<field name="language" type="string" nullable="true" /> |
||||
<field name="statement" type="string" nullable="true" /> |
||||
|
||||
<one-to-one field="instructor" target-entity="XApi\Repository\Doctrine\Mapping\StatementObject"> |
||||
<cascade> |
||||
<cascade-all /> |
||||
</cascade> |
||||
<join-column referenced-column-name="identifier" /> |
||||
</one-to-one> |
||||
<one-to-one field="team" target-entity="XApi\Repository\Doctrine\Mapping\StatementObject"> |
||||
<cascade> |
||||
<cascade-all /> |
||||
</cascade> |
||||
<join-column referenced-column-name="identifier" /> |
||||
</one-to-one> |
||||
<one-to-one field="extensions" target-entity="XApi\Repository\Doctrine\Mapping\Extensions"> |
||||
<cascade> |
||||
<cascade-all /> |
||||
</cascade> |
||||
<join-column referenced-column-name="identifier" /> |
||||
</one-to-one> |
||||
|
||||
<!-- context activities --> |
||||
<one-to-many field="parentActivities" target-entity="XApi\Repository\Doctrine\Mapping\StatementObject" mapped-by="parentContext"> |
||||
<cascade> |
||||
<cascade-all /> |
||||
</cascade> |
||||
</one-to-many> |
||||
<one-to-many field="groupingActivities" target-entity="XApi\Repository\Doctrine\Mapping\StatementObject" mapped-by="groupingContext"> |
||||
<cascade> |
||||
<cascade-all /> |
||||
</cascade> |
||||
</one-to-many> |
||||
<one-to-many field="categoryActivities" target-entity="XApi\Repository\Doctrine\Mapping\StatementObject" mapped-by="categoryContext"> |
||||
<cascade> |
||||
<cascade-all /> |
||||
</cascade> |
||||
</one-to-many> |
||||
<one-to-many field="otherActivities" target-entity="XApi\Repository\Doctrine\Mapping\StatementObject" mapped-by="otherContext"> |
||||
<cascade> |
||||
<cascade-all /> |
||||
</cascade> |
||||
</one-to-many> |
||||
</entity> |
||||
</doctrine-mapping> |
||||
@ -0,0 +1,13 @@ |
||||
<doctrine-mapping xmlns="http://doctrine-project.org/schemas/orm/doctrine-mapping" |
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |
||||
xsi:schemaLocation="http://doctrine-project.org/schemas/orm/doctrine-mapping |
||||
http://doctrine-project.org/schemas/orm/doctrine-mapping.xsd"> |
||||
|
||||
<entity name="XApi\Repository\Doctrine\Mapping\Extensions" table="xapi_extensions"> |
||||
<id name="identifier" type="integer"> |
||||
<generator strategy="AUTO" /> |
||||
</id> |
||||
|
||||
<field name="extensions" type="json_array" /> |
||||
</entity> |
||||
</doctrine-mapping> |
||||
@ -0,0 +1,28 @@ |
||||
<doctrine-mapping xmlns="http://doctrine-project.org/schemas/orm/doctrine-mapping" |
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |
||||
xsi:schemaLocation="http://doctrine-project.org/schemas/orm/doctrine-mapping |
||||
http://doctrine-project.org/schemas/orm/doctrine-mapping.xsd"> |
||||
|
||||
<entity name="XApi\Repository\Doctrine\Mapping\Result" table="xapi_result"> |
||||
<id name="identifier" type="integer"> |
||||
<generator strategy="AUTO" /> |
||||
</id> |
||||
|
||||
<field name="hasScore" type="boolean" /> |
||||
<field name="scaled" type="float" nullable="true" /> |
||||
<field name="raw" type="float" nullable="true" /> |
||||
<field name="min" type="float" nullable="true" /> |
||||
<field name="max" type="float" nullable="true" /> |
||||
<field name="success" type="boolean" nullable="true" /> |
||||
<field name="completion" type="boolean" nullable="true" /> |
||||
<field name="response" type="string" nullable="true" /> |
||||
<field name="duration" type="string" nullable="true" /> |
||||
|
||||
<one-to-one field="extensions" target-entity="XApi\Repository\Doctrine\Mapping\Extensions"> |
||||
<cascade> |
||||
<cascade-all /> |
||||
</cascade> |
||||
<join-column referenced-column-name="identifier" /> |
||||
</one-to-one> |
||||
</entity> |
||||
</doctrine-mapping> |
||||
@ -0,0 +1,62 @@ |
||||
<doctrine-mapping xmlns="http://doctrine-project.org/schemas/orm/doctrine-mapping" |
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |
||||
xsi:schemaLocation="http://doctrine-project.org/schemas/orm/doctrine-mapping |
||||
http://doctrine-project.org/schemas/orm/doctrine-mapping.xsd"> |
||||
|
||||
<entity name="XApi\Repository\Doctrine\Mapping\Statement" |
||||
repository-class="XApi\Repository\ORM\StatementRepository" |
||||
table="xapi_statement"> |
||||
|
||||
<id name="id" type="string"> |
||||
<generator strategy="NONE" /> |
||||
</id> |
||||
|
||||
<field name="created" type="bigint" nullable="true" /> |
||||
<field name="stored" type="bigint" nullable="true" /> |
||||
<field name="hasAttachments" type="boolean" /> |
||||
|
||||
<one-to-one field="actor" target-entity="XApi\Repository\Doctrine\Mapping\StatementObject"> |
||||
<cascade> |
||||
<cascade-all /> |
||||
</cascade> |
||||
<join-column referenced-column-name="identifier" /> |
||||
</one-to-one> |
||||
<one-to-one field="verb" target-entity="XApi\Repository\Doctrine\Mapping\Verb"> |
||||
<cascade> |
||||
<cascade-all /> |
||||
</cascade> |
||||
<join-column referenced-column-name="identifier" /> |
||||
</one-to-one> |
||||
<one-to-one field="object" target-entity="XApi\Repository\Doctrine\Mapping\StatementObject"> |
||||
<cascade> |
||||
<cascade-all /> |
||||
</cascade> |
||||
<join-column referenced-column-name="identifier" /> |
||||
</one-to-one> |
||||
<one-to-one field="result" target-entity="XApi\Repository\Doctrine\Mapping\Result"> |
||||
<cascade> |
||||
<cascade-all /> |
||||
</cascade> |
||||
<join-column referenced-column-name="identifier" /> |
||||
</one-to-one> |
||||
<one-to-one field="authority" target-entity="XApi\Repository\Doctrine\Mapping\StatementObject"> |
||||
<cascade> |
||||
<cascade-all /> |
||||
</cascade> |
||||
<join-column referenced-column-name="identifier" /> |
||||
</one-to-one> |
||||
<one-to-one field="context" target-entity="XApi\Repository\Doctrine\Mapping\Context"> |
||||
<cascade> |
||||
<cascade-all /> |
||||
</cascade> |
||||
<join-column referenced-column-name="identifier" /> |
||||
</one-to-one> |
||||
|
||||
<!-- attachments --> |
||||
<one-to-many field="attachments" target-entity="XApi\Repository\Doctrine\Mapping\Attachment" mapped-by="statement"> |
||||
<cascade> |
||||
<cascade-all /> |
||||
</cascade> |
||||
</one-to-many> |
||||
</entity> |
||||
</doctrine-mapping> |
||||
@ -0,0 +1,83 @@ |
||||
<doctrine-mapping xmlns="http://doctrine-project.org/schemas/orm/doctrine-mapping" |
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |
||||
xsi:schemaLocation="http://doctrine-project.org/schemas/orm/doctrine-mapping |
||||
http://doctrine-project.org/schemas/orm/doctrine-mapping.xsd"> |
||||
|
||||
<entity name="XApi\Repository\Doctrine\Mapping\StatementObject" table="xapi_object"> |
||||
<id name="identifier" type="integer"> |
||||
<generator strategy="AUTO" /> |
||||
</id> |
||||
|
||||
<!-- discriminator column --> |
||||
<field name="type" type="string" nullable="true" /> |
||||
|
||||
<!-- activity --> |
||||
<field name="activityId" type="string" nullable="true" /> |
||||
<field name="hasActivityDefinition" type="boolean" nullable="true" /> |
||||
<field name="hasActivityName" type="boolean" nullable="true" /> |
||||
<field name="activityName" type="json_array" nullable="true" /> |
||||
<field name="hasActivityDescription" type="boolean" nullable="true" /> |
||||
<field name="activityDescription" type="json_array" nullable="true" /> |
||||
<field name="activityType" type="string" nullable="true" /> |
||||
<field name="activityMoreInfo" type="string" nullable="true" /> |
||||
|
||||
<!-- actor --> |
||||
<field name="mbox" type="string" nullable="true" /> |
||||
<field name="mboxSha1Sum" type="string" nullable="true" /> |
||||
<field name="openId" type="string" nullable="true" /> |
||||
<field name="accountName" type="string" nullable="true" /> |
||||
<field name="accountHomePage" type="string" nullable="true" /> |
||||
<field name="name" type="string" nullable="true" /> |
||||
|
||||
<!-- statement reference --> |
||||
<field name="referencedStatementId" type="string" nullable="true" /> |
||||
|
||||
<!-- sub statement --> |
||||
<one-to-one field="actor" target-entity="XApi\Repository\Doctrine\Mapping\StatementObject"> |
||||
<cascade> |
||||
<cascade-all /> |
||||
</cascade> |
||||
<join-column referenced-column-name="identifier" /> |
||||
</one-to-one> |
||||
<one-to-one field="verb" target-entity="XApi\Repository\Doctrine\Mapping\Verb"> |
||||
<cascade> |
||||
<cascade-all /> |
||||
</cascade> |
||||
<join-column referenced-column-name="identifier" /> |
||||
</one-to-one> |
||||
<one-to-one field="object" target-entity="XApi\Repository\Doctrine\Mapping\StatementObject"> |
||||
<cascade> |
||||
<cascade-all /> |
||||
</cascade> |
||||
<join-column referenced-column-name="identifier" /> |
||||
</one-to-one> |
||||
|
||||
<!-- activity extensions --> |
||||
<one-to-one field="activityExtensions" target-entity="XApi\Repository\Doctrine\Mapping\Extensions"> |
||||
<cascade> |
||||
<cascade-all /> |
||||
</cascade> |
||||
<join-column referenced-column-name="identifier" /> |
||||
</one-to-one> |
||||
|
||||
<!-- group members --> |
||||
<one-to-many target-entity="XApi\Repository\Doctrine\Mapping\StatementObject" mapped-by="group" field="members" /> |
||||
<many-to-one target-entity="XApi\Repository\Doctrine\Mapping\StatementObject" field="group" inversed-by="members"> |
||||
<join-column referenced-column-name="identifier" /> |
||||
</many-to-one> |
||||
|
||||
<!-- context activities --> |
||||
<many-to-one target-entity="XApi\Repository\Doctrine\Mapping\Context" field="parentContext" inversed-by="parentActivities"> |
||||
<join-column referenced-column-name="identifier" /> |
||||
</many-to-one> |
||||
<many-to-one target-entity="XApi\Repository\Doctrine\Mapping\Context" field="groupingContext" inversed-by="groupingActivities"> |
||||
<join-column referenced-column-name="identifier" /> |
||||
</many-to-one> |
||||
<many-to-one target-entity="XApi\Repository\Doctrine\Mapping\Context" field="categoryContext" inversed-by="categoryActivities"> |
||||
<join-column referenced-column-name="identifier" /> |
||||
</many-to-one> |
||||
<many-to-one target-entity="XApi\Repository\Doctrine\Mapping\Context" field="otherContext" inversed-by="otherActivities"> |
||||
<join-column referenced-column-name="identifier" /> |
||||
</many-to-one> |
||||
</entity> |
||||
</doctrine-mapping> |
||||
@ -0,0 +1,14 @@ |
||||
<doctrine-mapping xmlns="http://doctrine-project.org/schemas/orm/doctrine-mapping" |
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |
||||
xsi:schemaLocation="http://doctrine-project.org/schemas/orm/doctrine-mapping |
||||
http://doctrine-project.org/schemas/orm/doctrine-mapping.xsd"> |
||||
|
||||
<entity name="XApi\Repository\Doctrine\Mapping\Verb" table="xapi_verb"> |
||||
<id name="identifier" type="integer"> |
||||
<generator strategy="AUTO" /> |
||||
</id> |
||||
|
||||
<field name="id" type="string" /> |
||||
<field name="display" type="json_array" /> |
||||
</entity> |
||||
</doctrine-mapping> |
||||
@ -0,0 +1,13 @@ |
||||
<?xml version="1.0" encoding="UTF-8"?> |
||||
<phpunit colors="true" bootstrap="vendor/autoload.php"> |
||||
<testsuites> |
||||
<testsuite name="Doctrine ORM driver implementation for an xAPI repository"> |
||||
<directory>./tests</directory> |
||||
</testsuite> |
||||
</testsuites> |
||||
<filter> |
||||
<whitelist> |
||||
<directory>./src</directory> |
||||
</whitelist> |
||||
</filter> |
||||
</phpunit> |
||||
@ -0,0 +1,50 @@ |
||||
<?php |
||||
|
||||
/* |
||||
* This file is part of the xAPI package. |
||||
* |
||||
* (c) Christian Flothmann <christian.flothmann@xabbuh.de> |
||||
* |
||||
* For the full copyright and license information, please view the LICENSE |
||||
* file that was distributed with this source code. |
||||
*/ |
||||
|
||||
namespace XApi\Repository\ORM; |
||||
|
||||
use Doctrine\ORM\EntityRepository; |
||||
use XApi\Repository\Doctrine\Mapping\Statement; |
||||
use XApi\Repository\Doctrine\Repository\Mapping\StatementRepository as BaseStatementRepository; |
||||
|
||||
/** |
||||
* @author Christian Flothmann <christian.flothmann@xabbuh.de> |
||||
*/ |
||||
final class StatementRepository extends EntityRepository implements BaseStatementRepository |
||||
{ |
||||
/** |
||||
* {@inheritdoc} |
||||
*/ |
||||
public function findStatement(array $criteria) |
||||
{ |
||||
return parent::findOneBy($criteria); |
||||
} |
||||
|
||||
/** |
||||
* {@inheritdoc} |
||||
*/ |
||||
public function findStatements(array $criteria) |
||||
{ |
||||
return parent::findBy($criteria); |
||||
} |
||||
|
||||
/** |
||||
* {@inheritdoc} |
||||
*/ |
||||
public function storeStatement(Statement $mappedStatement, $flush = true) |
||||
{ |
||||
$this->_em->persist($mappedStatement); |
||||
|
||||
if ($flush) { |
||||
$this->_em->flush(); |
||||
} |
||||
} |
||||
} |
||||
@ -0,0 +1,52 @@ |
||||
<?php |
||||
|
||||
/* |
||||
* This file is part of the xAPI package. |
||||
* |
||||
* (c) Christian Flothmann <christian.flothmann@xabbuh.de> |
||||
* |
||||
* For the full copyright and license information, please view the LICENSE |
||||
* file that was distributed with this source code. |
||||
*/ |
||||
|
||||
namespace XApi\Repository\ORM\Tests\Functional; |
||||
|
||||
use Doctrine\Common\Persistence\Mapping\Driver\SymfonyFileLocator; |
||||
use Doctrine\ORM\Configuration; |
||||
use Doctrine\ORM\EntityManager; |
||||
use Doctrine\ORM\Mapping\Driver\XmlDriver; |
||||
use Doctrine\ORM\Tools\SchemaTool; |
||||
use XApi\Repository\Doctrine\Test\Functional\StatementRepositoryTest as BaseStatementRepositoryTest; |
||||
|
||||
class StatementRepositoryTest extends BaseStatementRepositoryTest |
||||
{ |
||||
protected function createObjectManager() |
||||
{ |
||||
$config = new Configuration(); |
||||
$config->setProxyDir(__DIR__.'/../proxies'); |
||||
$config->setProxyNamespace('Proxy'); |
||||
$fileLocator = new SymfonyFileLocator( |
||||
array(__DIR__.'/../../metadata' => 'XApi\Repository\Doctrine\Mapping'), |
||||
'.orm.xml' |
||||
); |
||||
$driver = new XmlDriver($fileLocator); |
||||
$config->setMetadataDriverImpl($driver); |
||||
|
||||
return EntityManager::create(array('driver' => 'pdo_sqlite', 'path' => __DIR__.'/../data/db.sqlite'), $config); |
||||
} |
||||
|
||||
protected function getStatementClassName() |
||||
{ |
||||
return 'XApi\Repository\Doctrine\Mapping\Statement'; |
||||
} |
||||
|
||||
protected function cleanDatabase() |
||||
{ |
||||
$metadata = $this->objectManager->getMetadataFactory()->getAllMetadata(); |
||||
$tool = new SchemaTool($this->objectManager); |
||||
$tool->dropDatabase(); |
||||
$tool->createSchema($metadata); |
||||
|
||||
parent::cleanDatabase(); |
||||
} |
||||
} |
||||
@ -0,0 +1,38 @@ |
||||
<?php |
||||
|
||||
/* |
||||
* This file is part of the xAPI package. |
||||
* |
||||
* (c) Christian Flothmann <christian.flothmann@xabbuh.de> |
||||
* |
||||
* For the full copyright and license information, please view the LICENSE |
||||
* file that was distributed with this source code. |
||||
*/ |
||||
|
||||
namespace XApi\Repository\ORM\Tests\Unit\Repository; |
||||
|
||||
use XApi\Repository\Doctrine\Test\Unit\Repository\Mapping\StatementRepositoryTest as BaseStatementRepositoryTest; |
||||
use XApi\Repository\ORM\StatementRepository; |
||||
|
||||
class StatementRepositoryTest extends BaseStatementRepositoryTest |
||||
{ |
||||
protected function getObjectManagerClass() |
||||
{ |
||||
return 'Doctrine\ORM\EntityManager'; |
||||
} |
||||
|
||||
protected function getUnitOfWorkClass() |
||||
{ |
||||
return 'Doctrine\ORM\UnitOfWork'; |
||||
} |
||||
|
||||
protected function getClassMetadataClass() |
||||
{ |
||||
return 'Doctrine\ORM\Mapping\ClassMetadata'; |
||||
} |
||||
|
||||
protected function createMappedStatementRepository($objectManager, $unitOfWork, $classMetadata) |
||||
{ |
||||
return new StatementRepository($objectManager, $classMetadata); |
||||
} |
||||
} |
||||
@ -1,161 +0,0 @@ |
||||
<?php |
||||
|
||||
/* |
||||
* This file is part of the xAPI package. |
||||
* |
||||
* (c) Christian Flothmann <christian.flothmann@xabbuh.de> |
||||
* |
||||
* For the full copyright and license information, please view the LICENSE |
||||
* file that was distributed with this source code. |
||||
*/ |
||||
|
||||
namespace Chamilo\PluginBundle\Entity\XApi\Lrs; |
||||
|
||||
use Doctrine\ORM\Mapping as ORM; |
||||
use Xabbuh\XApi\Model\Account; |
||||
use Xabbuh\XApi\Model\Actor as ActorModel; |
||||
use Xabbuh\XApi\Model\Agent; |
||||
use Xabbuh\XApi\Model\Group; |
||||
use Xabbuh\XApi\Model\InverseFunctionalIdentifier; |
||||
use Xabbuh\XApi\Model\IRI; |
||||
use Xabbuh\XApi\Model\IRL; |
||||
|
||||
/** |
||||
* @author Christian Flothmann <christian.flothmann@xabbuh.de> |
||||
* |
||||
* @ORM\Table(name="xapi_actor") |
||||
* @ORM\Entity() |
||||
*/ |
||||
class Actor |
||||
{ |
||||
/** |
||||
* @var int |
||||
* |
||||
* @ORM\Id() |
||||
* @ORM\GeneratedValue() |
||||
* @ORM\Column(type="integer") |
||||
*/ |
||||
public $identifier; |
||||
|
||||
/** |
||||
* @var string |
||||
* |
||||
* @ORM\Column(type="string", nullable=true) |
||||
*/ |
||||
public $type; |
||||
|
||||
/** |
||||
* @var string|null |
||||
* |
||||
* @ORM\Column(type="string", nullable=true) |
||||
*/ |
||||
public $mbox; |
||||
|
||||
/** |
||||
* @var string|null |
||||
* |
||||
* @ORM\Column(type="string", nullable=true) |
||||
*/ |
||||
public $mboxSha1Sum; |
||||
|
||||
/** |
||||
* @var string|null |
||||
* |
||||
* @ORM\Column(type="string", nullable=true) |
||||
*/ |
||||
public $openId; |
||||
|
||||
/** |
||||
* @var string|null |
||||
* |
||||
* @ORM\Column(type="string", nullable=true) |
||||
*/ |
||||
public $accountName; |
||||
|
||||
/** |
||||
* @var string|null |
||||
* |
||||
* @ORM\Column(type="string", nullable=true) |
||||
*/ |
||||
public $accountHomePage; |
||||
|
||||
/** |
||||
* @var string|null |
||||
* |
||||
* @ORM\Column(type="string", nullable=true) |
||||
*/ |
||||
public $name; |
||||
|
||||
/** |
||||
* @var Actor[]|null |
||||
* |
||||
* @ORM\Column() |
||||
*/ |
||||
public $members; |
||||
|
||||
/** |
||||
* @param \Xabbuh\XApi\Model\Actor $model |
||||
* |
||||
* @return \Chamilo\PluginBundle\Entity\XApi\Lrs\Actor |
||||
*/ |
||||
public static function fromModel(ActorModel $model) |
||||
{ |
||||
$inverseFunctionalIdentifier = $model->getInverseFunctionalIdentifier(); |
||||
|
||||
$actor = new self(); |
||||
$actor->mboxSha1Sum = $inverseFunctionalIdentifier->getMboxSha1Sum(); |
||||
$actor->openId = $inverseFunctionalIdentifier->getOpenId(); |
||||
|
||||
if (null !== $mbox = $inverseFunctionalIdentifier->getMbox()) { |
||||
$actor->mbox = $mbox->getValue(); |
||||
} |
||||
|
||||
if (null !== $account = $inverseFunctionalIdentifier->getAccount()) { |
||||
$actor->accountName = $account->getName(); |
||||
$actor->accountHomePage = $account->getHomePage()->getValue(); |
||||
} |
||||
|
||||
if ($model instanceof Group) { |
||||
$actor->type = 'group'; |
||||
$actor->members = array(); |
||||
|
||||
foreach ($model->getMembers() as $agent) { |
||||
$actor->members[] = Actor::fromModel($agent); |
||||
} |
||||
} else { |
||||
$actor->type = 'agent'; |
||||
} |
||||
|
||||
return $actor; |
||||
} |
||||
|
||||
/** |
||||
* @return \Xabbuh\XApi\Model\Agent|\Xabbuh\XApi\Model\Group |
||||
*/ |
||||
public function getModel() |
||||
{ |
||||
$inverseFunctionalIdentifier = null; |
||||
|
||||
if (null !== $this->mbox) { |
||||
$inverseFunctionalIdentifier = InverseFunctionalIdentifier::withMbox(IRI::fromString($this->mbox)); |
||||
} elseif (null !== $this->mboxSha1Sum) { |
||||
$inverseFunctionalIdentifier = InverseFunctionalIdentifier::withMboxSha1Sum($this->mboxSha1Sum); |
||||
} elseif (null !== $this->openId) { |
||||
$inverseFunctionalIdentifier = InverseFunctionalIdentifier::withOpenId($this->openId); |
||||
} elseif (null !== $this->accountName && null !== $this->accountHomePage) { |
||||
$inverseFunctionalIdentifier = InverseFunctionalIdentifier::withAccount(new Account($this->accountName, IRL::fromString($this->accountHomePage))); |
||||
} |
||||
|
||||
if ('group' === $this->type) { |
||||
$members = array(); |
||||
|
||||
foreach ($this->members as $agent) { |
||||
$members[] = $agent->getModel(); |
||||
} |
||||
|
||||
return new Group($inverseFunctionalIdentifier, $this->name, $members); |
||||
} |
||||
|
||||
return new Agent($inverseFunctionalIdentifier, $this->name); |
||||
} |
||||
} |
||||
@ -1,163 +0,0 @@ |
||||
<?php |
||||
|
||||
/* |
||||
* This file is part of the xAPI package. |
||||
* |
||||
* (c) Christian Flothmann <christian.flothmann@xabbuh.de> |
||||
* |
||||
* For the full copyright and license information, please view the LICENSE |
||||
* file that was distributed with this source code. |
||||
*/ |
||||
|
||||
namespace Chamilo\PluginBundle\Entity\XApi\Lrs; |
||||
|
||||
use Doctrine\ORM\Mapping as ORM; |
||||
use Xabbuh\XApi\Model\Attachment as AttachmentModel; |
||||
use Xabbuh\XApi\Model\IRI; |
||||
use Xabbuh\XApi\Model\IRL; |
||||
use Xabbuh\XApi\Model\LanguageMap; |
||||
|
||||
/** |
||||
* @author Christian Flothmann <christian.flothmann@xabbuh.de> |
||||
* |
||||
* @ORM\Table(name="xapi_attachment") |
||||
* @ORM\Entity() |
||||
*/ |
||||
class Attachment |
||||
{ |
||||
/** |
||||
* @var int |
||||
* |
||||
* @ORM\Id() |
||||
* @ORM\GeneratedValue() |
||||
* @ORM\Column(type="integer") |
||||
*/ |
||||
public $identifier; |
||||
|
||||
/** |
||||
* @ORM\ManyToOne(targetEntity="Chamilo\PluginBundle\Entity\XApi\Lrs\Statement", inversedBy="attachments") |
||||
*/ |
||||
public $statement; |
||||
|
||||
/** |
||||
* @var string |
||||
* |
||||
* @ORM\Column(type="string") |
||||
*/ |
||||
public $usageType; |
||||
|
||||
/** |
||||
* @var string |
||||
* |
||||
* @ORM\Column(type="string") |
||||
*/ |
||||
public $contentType; |
||||
|
||||
/** |
||||
* @var int |
||||
* |
||||
* @ORM\Column(type="integer") |
||||
*/ |
||||
public $length; |
||||
|
||||
/** |
||||
* @var string |
||||
* |
||||
* @ORM\Column(type="string") |
||||
*/ |
||||
public $sha2; |
||||
|
||||
/** |
||||
* @var array |
||||
* |
||||
* @ORM\Column(type="json") |
||||
*/ |
||||
public $display; |
||||
|
||||
/** |
||||
* @var bool |
||||
* |
||||
* @ORM\Column(type="boolean") |
||||
*/ |
||||
public $hasDescription; |
||||
|
||||
/** |
||||
* @var array|null |
||||
* |
||||
* @ORM\Column(type="json", nullable=true) |
||||
*/ |
||||
public $description; |
||||
|
||||
/** |
||||
* @var string|null |
||||
* |
||||
* @ORM\Column(type="string", nullable=true) |
||||
*/ |
||||
public $fileUrl; |
||||
|
||||
/** |
||||
* @var string|null |
||||
* |
||||
* @ORM\Column(type="text", nullable=true) |
||||
*/ |
||||
public $content; |
||||
|
||||
/** |
||||
* @param \Xabbuh\XApi\Model\Attachment $model |
||||
* |
||||
* @return \Chamilo\PluginBundle\Entity\XApi\Lrs\Attachment |
||||
*/ |
||||
public static function fromModel(AttachmentModel $model) |
||||
{ |
||||
$attachment = new self(); |
||||
$attachment->usageType = $model->getUsageType()->getValue(); |
||||
$attachment->contentType = $model->getContentType(); |
||||
$attachment->length = $model->getLength(); |
||||
$attachment->sha2 = $model->getSha2(); |
||||
$attachment->display = array(); |
||||
|
||||
if (null !== $model->getFileUrl()) { |
||||
$attachment->fileUrl = $model->getFileUrl()->getValue(); |
||||
} |
||||
|
||||
$attachment->content = $model->getContent(); |
||||
|
||||
$display = $model->getDisplay(); |
||||
|
||||
foreach ($display->languageTags() as $languageTag) { |
||||
$attachment->display[$languageTag] = $display[$languageTag]; |
||||
} |
||||
|
||||
if (null !== $description = $model->getDescription()) { |
||||
$attachment->hasDescription = true; |
||||
$attachment->description = array(); |
||||
|
||||
foreach ($description->languageTags() as $languageTag) { |
||||
$attachment->description[$languageTag] = $description[$languageTag]; |
||||
} |
||||
} else { |
||||
$attachment->hasDescription = false; |
||||
} |
||||
|
||||
return $attachment; |
||||
} |
||||
|
||||
/** |
||||
* @return \Xabbuh\XApi\Model\Attachment |
||||
*/ |
||||
public function getModel() |
||||
{ |
||||
$description = null; |
||||
$fileUrl = null; |
||||
|
||||
if ($this->hasDescription) { |
||||
$description = LanguageMap::create($this->description); |
||||
} |
||||
|
||||
if (null !== $this->fileUrl) { |
||||
$fileUrl = IRL::fromString($this->fileUrl); |
||||
} |
||||
|
||||
return new AttachmentModel(IRI::fromString($this->usageType), $this->contentType, $this->length, $this->sha2, LanguageMap::create($this->display), $description, $fileUrl, $this->content); |
||||
} |
||||
} |
||||
@ -1,268 +0,0 @@ |
||||
<?php |
||||
|
||||
/* |
||||
* This file is part of the xAPI package. |
||||
* |
||||
* (c) Christian Flothmann <christian.flothmann@xabbuh.de> |
||||
* |
||||
* For the full copyright and license information, please view the LICENSE |
||||
* file that was distributed with this source code. |
||||
*/ |
||||
|
||||
namespace Chamilo\PluginBundle\Entity\XApi\Lrs; |
||||
|
||||
use Doctrine\ORM\Mapping as ORM; |
||||
use Xabbuh\XApi\Model\Context as ContextModel; |
||||
use Xabbuh\XApi\Model\ContextActivities; |
||||
use Xabbuh\XApi\Model\StatementId; |
||||
use Xabbuh\XApi\Model\StatementReference; |
||||
|
||||
/** |
||||
* @author Christian Flothmann <christian.flothmann@xabbuh.de> |
||||
* |
||||
* @ORM\Table(name="xapi_context") |
||||
* @ORM\Entity() |
||||
*/ |
||||
class Context |
||||
{ |
||||
/** |
||||
* @var int |
||||
* |
||||
* @ORM\Id() |
||||
* @ORM\GeneratedValue() |
||||
* @ORM\Column(type="integer") |
||||
*/ |
||||
public $identifier; |
||||
|
||||
/** |
||||
* @var string|null |
||||
* |
||||
* @ORM\Column(type="string", nullable=true) |
||||
*/ |
||||
public $registration; |
||||
|
||||
/** |
||||
* @var StatementObject|null |
||||
* |
||||
* @ORM\OneToOne(targetEntity="Chamilo\PluginBundle\Entity\XApi\Lrs\StatementObject", cascade={"ALL"}) |
||||
* @ORM\JoinColumn(referencedColumnName="identifier") |
||||
*/ |
||||
public $instructor; |
||||
|
||||
/** |
||||
* @var StatementObject|null |
||||
* |
||||
* @ORM\OneToOne(targetEntity="Chamilo\PluginBundle\Entity\XApi\Lrs\StatementObject", cascade={"ALL"}) |
||||
* @ORM\JoinColumn(referencedColumnName="identifier") |
||||
*/ |
||||
public $team; |
||||
|
||||
/** |
||||
* @var bool|null |
||||
* |
||||
* @ORM\Column(name="hasContextActivities", type="boolean", nullable=true) |
||||
*/ |
||||
public $hasContextActivities; |
||||
|
||||
/** |
||||
* @var StatementObject[]|null |
||||
* |
||||
* @ORM\OneToMany(targetEntity="Chamilo\PluginBundle\Entity\XApi\Lrs\StatementObject", mappedBy="parentContext", cascade={"ALL"}) |
||||
*/ |
||||
public $parentActivities; |
||||
|
||||
/** |
||||
* @var StatementObject[]|null |
||||
* |
||||
* @ORM\OneToMany(targetEntity="Chamilo\PluginBundle\Entity\XApi\Lrs\StatementObject", mappedBy="groupingContext", cascade={"ALL"}) |
||||
*/ |
||||
public $groupingActivities; |
||||
|
||||
/** |
||||
* @var StatementObject[]|null |
||||
* |
||||
* @ORM\OneToMany(targetEntity="Chamilo\PluginBundle\Entity\XApi\Lrs\StatementObject", mappedBy="categoryContext", cascade={"ALL"}) |
||||
*/ |
||||
public $categoryActivities; |
||||
|
||||
/** |
||||
* @var StatementObject[]|null |
||||
* |
||||
* @ORM\OneToMany(targetEntity="Chamilo\PluginBundle\Entity\XApi\Lrs\StatementObject", mappedBy="otherContext", cascade={"ALL"}) |
||||
*/ |
||||
public $otherActivities; |
||||
|
||||
/** |
||||
* @var string|null |
||||
* |
||||
* @ORM\Column(type="string", nullable=true) |
||||
*/ |
||||
public $revision; |
||||
|
||||
/** |
||||
* @var string|null |
||||
* |
||||
* @ORM\Column(type="string", nullable=true) |
||||
*/ |
||||
public $platform; |
||||
|
||||
/** |
||||
* @var string|null |
||||
* |
||||
* @ORM\Column(type="string", nullable=true) |
||||
*/ |
||||
public $language; |
||||
|
||||
/** |
||||
* @var string|null |
||||
* |
||||
* @ORM\Column(type="string", nullable=true) |
||||
*/ |
||||
public $statement; |
||||
|
||||
/** |
||||
* @var Extensions|null |
||||
* |
||||
* @ORM\OneToOne(targetEntity="Chamilo\PluginBundle\Entity\XApi\Lrs\Extensions", cascade={"ALL"}) |
||||
* @ORM\JoinColumn(referencedColumnName="identifier") |
||||
*/ |
||||
public $extensions; |
||||
|
||||
/** |
||||
* @param \Xabbuh\XApi\Model\Context $model |
||||
* |
||||
* @return \Chamilo\PluginBundle\Entity\XApi\Lrs\Context |
||||
*/ |
||||
public static function fromModel(ContextModel $model) |
||||
{ |
||||
$context = new self(); |
||||
$context->registration = $model->getRegistration(); |
||||
$context->revision = $model->getRevision(); |
||||
$context->platform = $model->getPlatform(); |
||||
$context->language = $model->getLanguage(); |
||||
|
||||
if (null !== $instructor = $model->getInstructor()) { |
||||
$context->instructor = StatementObject::fromModel($instructor); |
||||
} |
||||
|
||||
if (null !== $team = $model->getTeam()) { |
||||
$context->team = StatementObject::fromModel($team); |
||||
} |
||||
|
||||
if (null !== $contextActivities = $model->getContextActivities()) { |
||||
$context->hasContextActivities = true; |
||||
|
||||
if (null !== $parentActivities = $contextActivities->getParentActivities()) { |
||||
$context->parentActivities = array(); |
||||
|
||||
foreach ($parentActivities as $parentActivity) { |
||||
$activity = StatementObject::fromModel($parentActivity); |
||||
$activity->parentContext = $context; |
||||
$context->parentActivities[] = $activity; |
||||
} |
||||
} |
||||
|
||||
if (null !== $groupingActivities = $contextActivities->getGroupingActivities()) { |
||||
$context->groupingActivities = array(); |
||||
|
||||
foreach ($groupingActivities as $groupingActivity) { |
||||
$activity = StatementObject::fromModel($groupingActivity); |
||||
$activity->groupingContext = $context; |
||||
$context->groupingActivities[] = $activity; |
||||
} |
||||
} |
||||
|
||||
if (null !== $categoryActivities = $contextActivities->getCategoryActivities()) { |
||||
$context->categoryActivities = array(); |
||||
|
||||
foreach ($categoryActivities as $categoryActivity) { |
||||
$activity = StatementObject::fromModel($categoryActivity); |
||||
$activity->categoryContext = $context; |
||||
$context->categoryActivities[] = $activity; |
||||
} |
||||
} |
||||
|
||||
if (null !== $otherActivities = $contextActivities->getOtherActivities()) { |
||||
$context->otherActivities = array(); |
||||
|
||||
foreach ($otherActivities as $otherActivity) { |
||||
$activity = StatementObject::fromModel($otherActivity); |
||||
$activity->otherContext = $context; |
||||
$context->otherActivities[] = $activity; |
||||
} |
||||
} |
||||
} else { |
||||
$context->hasContextActivities = false; |
||||
} |
||||
|
||||
if (null !== $statementReference = $model->getStatement()) { |
||||
$context->statement = $statementReference->getStatementId()->getValue(); |
||||
} |
||||
|
||||
if (null !== $contextExtensions = $model->getExtensions()) { |
||||
$context->extensions = Extensions::fromModel($contextExtensions); |
||||
} |
||||
|
||||
return $context; |
||||
} |
||||
|
||||
/** |
||||
* @return \Xabbuh\XApi\Model\Context |
||||
*/ |
||||
public function getModel() |
||||
{ |
||||
$context = new ContextModel(); |
||||
$context = $context->withRegistration($this->registration); |
||||
$context = $context->withRevision($this->revision); |
||||
$context = $context->withPlatform($this->platform); |
||||
$context = $context->withLanguage($this->language); |
||||
|
||||
if (null !== $this->instructor) { |
||||
$context = $context->withInstructor($this->instructor->getModel()); |
||||
} |
||||
|
||||
if (null !== $this->team) { |
||||
$context = $context->withTeam($this->team->getModel()); |
||||
} |
||||
|
||||
if ($this->hasContextActivities) { |
||||
$contextActivities = new ContextActivities(); |
||||
|
||||
if (null !== $this->parentActivities) { |
||||
foreach ($this->parentActivities as $contextParentActivity) { |
||||
$contextActivities = $contextActivities->withAddedParentActivity($contextParentActivity->getModel()); |
||||
} |
||||
} |
||||
|
||||
if (null !== $this->groupingActivities) { |
||||
foreach ($this->groupingActivities as $contextGroupingActivity) { |
||||
$contextActivities = $contextActivities->withAddedGroupingActivity($contextGroupingActivity->getModel()); |
||||
} |
||||
} |
||||
|
||||
if (null !== $this->categoryActivities) { |
||||
foreach ($this->categoryActivities as $contextCategoryActivity) { |
||||
$contextActivities = $contextActivities->withAddedCategoryActivity($contextCategoryActivity->getModel()); |
||||
} |
||||
} |
||||
|
||||
if (null !== $this->otherActivities) { |
||||
foreach ($this->otherActivities as $contextOtherActivity) { |
||||
$contextActivities = $contextActivities->withAddedOtherActivity($contextOtherActivity->getModel()); |
||||
} |
||||
} |
||||
|
||||
$context = $context->withContextActivities($contextActivities); |
||||
} |
||||
|
||||
if (null !== $this->statement) { |
||||
$context = $context->withStatement(new StatementReference(StatementId::fromString($this->statement))); |
||||
} |
||||
|
||||
if (null !== $this->extensions) { |
||||
$context = $context->withExtensions($this->extensions->getModel()); |
||||
} |
||||
|
||||
return $context; |
||||
} |
||||
} |
||||
@ -1,71 +0,0 @@ |
||||
<?php |
||||
|
||||
/* |
||||
* This file is part of the xAPI package. |
||||
* |
||||
* (c) Christian Flothmann <christian.flothmann@xabbuh.de> |
||||
* |
||||
* For the full copyright and license information, please view the LICENSE |
||||
* file that was distributed with this source code. |
||||
*/ |
||||
|
||||
namespace Chamilo\PluginBundle\Entity\XApi\Lrs; |
||||
|
||||
use Doctrine\ORM\Mapping as ORM; |
||||
use Xabbuh\XApi\Model\Extensions as ExtensionsModel; |
||||
use Xabbuh\XApi\Model\IRI; |
||||
|
||||
/** |
||||
* @author Christian Flothmann <christian.flothmann@xabbuh.de> |
||||
* |
||||
* @ORM\Table(name="xapi_extensions") |
||||
* @ORM\Entity() |
||||
*/ |
||||
class Extensions |
||||
{ |
||||
/** |
||||
* @var int |
||||
* |
||||
* @ORM\Id() |
||||
* @ORM\GeneratedValue() |
||||
* @ORM\Column(type="integer") |
||||
*/ |
||||
public $identifier; |
||||
/** |
||||
* @var array |
||||
* |
||||
* @ORM\Column(type="json") |
||||
*/ |
||||
public $extensions; |
||||
|
||||
/** |
||||
* @param \Xabbuh\XApi\Model\Extensions $model |
||||
* |
||||
* @return \Chamilo\PluginBundle\Entity\XApi\Lrs\Extensions |
||||
*/ |
||||
public static function fromModel(ExtensionsModel $model) |
||||
{ |
||||
$extensions = new self(); |
||||
$extensions->extensions = array(); |
||||
|
||||
foreach ($model->getExtensions() as $key) { |
||||
$extensions->extensions[$key->getValue()] = $model[$key]; |
||||
} |
||||
|
||||
return $extensions; |
||||
} |
||||
|
||||
/** |
||||
* @return \Xabbuh\XApi\Model\Extensions |
||||
*/ |
||||
public function getModel() |
||||
{ |
||||
$extensions = new \SplObjectStorage(); |
||||
|
||||
foreach ($this->extensions as $key => $extension) { |
||||
$extensions->attach(IRI::fromString($key), $extension); |
||||
} |
||||
|
||||
return new ExtensionsModel($extensions); |
||||
} |
||||
} |
||||
@ -1,154 +0,0 @@ |
||||
<?php |
||||
|
||||
/* |
||||
* This file is part of the xAPI package. |
||||
* |
||||
* (c) Christian Flothmann <christian.flothmann@xabbuh.de> |
||||
* |
||||
* For the full copyright and license information, please view the LICENSE |
||||
* file that was distributed with this source code. |
||||
*/ |
||||
|
||||
namespace Chamilo\PluginBundle\Entity\XApi\Lrs; |
||||
|
||||
use Doctrine\ORM\Mapping as ORM; |
||||
use Xabbuh\XApi\Model\Result as ResultModel; |
||||
use Xabbuh\XApi\Model\Score; |
||||
|
||||
/** |
||||
* @author Christian Flothmann <christian.flothmann@xabbuh.de> |
||||
* |
||||
* @ORM\Table(name="xapi_result") |
||||
* @ORM\Entity() |
||||
*/ |
||||
class Result |
||||
{ |
||||
/** |
||||
* @var int |
||||
* |
||||
* @ORM\Id() |
||||
* @ORM\GeneratedValue() |
||||
* @ORM\Column(type="integer") |
||||
*/ |
||||
public $identifier; |
||||
|
||||
/** |
||||
* @var bool |
||||
* |
||||
* @ORM\Column(type="boolean") |
||||
*/ |
||||
public $hasScore; |
||||
|
||||
/** |
||||
* @var float|null |
||||
* |
||||
* @ORM\Column(type="float", nullable=true) |
||||
*/ |
||||
public $scaled; |
||||
|
||||
/** |
||||
* @var float|null |
||||
* |
||||
* @ORM\Column(type="float", nullable=true) |
||||
*/ |
||||
public $raw; |
||||
|
||||
/** |
||||
* @var float|null |
||||
* |
||||
* @ORM\Column(type="float", nullable=true) |
||||
*/ |
||||
public $min; |
||||
|
||||
/** |
||||
* @var float|null |
||||
* |
||||
* @ORM\Column(type="float", nullable=true) |
||||
*/ |
||||
public $max; |
||||
|
||||
/** |
||||
* @var bool|null |
||||
* |
||||
* @ORM\Column(type="boolean", nullable=true) |
||||
*/ |
||||
public $success; |
||||
|
||||
/** |
||||
* @var bool|null |
||||
* |
||||
* @ORM\Column(type="boolean", nullable=true) |
||||
*/ |
||||
public $completion; |
||||
|
||||
/** |
||||
* @var string|null |
||||
* |
||||
* @ORM\Column(type="string", nullable=true) |
||||
*/ |
||||
public $response; |
||||
|
||||
/** |
||||
* @var string|null |
||||
* |
||||
* @ORM\Column(type="string", nullable=true) |
||||
*/ |
||||
public $duration; |
||||
|
||||
/** |
||||
* @var Extensions|null |
||||
* |
||||
* @ORM\OneToOne(targetEntity="Chamilo\PluginBundle\Entity\XApi\Lrs\Extensions", cascade={"ALL"}) |
||||
* @ORM\JoinColumn(referencedColumnName="identifier") |
||||
*/ |
||||
public $extensions; |
||||
|
||||
/** |
||||
* @param \Xabbuh\XApi\Model\Result $model |
||||
* |
||||
* @return \Chamilo\PluginBundle\Entity\XApi\Lrs\Result |
||||
*/ |
||||
public static function fromModel(ResultModel $model) |
||||
{ |
||||
$result = new self(); |
||||
$result->success = $model->getSuccess(); |
||||
$result->completion = $model->getCompletion(); |
||||
$result->response = $model->getResponse(); |
||||
$result->duration = $model->getDuration(); |
||||
|
||||
if (null !== $score = $model->getScore()) { |
||||
$result->hasScore = true; |
||||
$result->scaled = $score->getScaled(); |
||||
$result->raw = $score->getRaw(); |
||||
$result->min = $score->getMin(); |
||||
$result->max = $score->getMax(); |
||||
} else { |
||||
$result->hasScore = false; |
||||
} |
||||
|
||||
if (null !== $extensions = $model->getExtensions()) { |
||||
$result->extensions = Extensions::fromModel($extensions); |
||||
} |
||||
|
||||
return $result; |
||||
} |
||||
|
||||
/** |
||||
* @return \Xabbuh\XApi\Model\Result |
||||
*/ |
||||
public function getModel() |
||||
{ |
||||
$score = null; |
||||
$extensions = null; |
||||
|
||||
if ($this->hasScore) { |
||||
$score = new Score($this->scaled, $this->raw, $this->min, $this->max); |
||||
} |
||||
|
||||
if (null !== $this->extensions) { |
||||
$extensions = $this->extensions->getModel(); |
||||
} |
||||
|
||||
return new ResultModel($score, $this->success, $this->completion, $this->response, $this->duration, $extensions); |
||||
} |
||||
} |
||||
@ -1,212 +0,0 @@ |
||||
<?php |
||||
|
||||
/* |
||||
* This file is part of the xAPI package. |
||||
* |
||||
* (c) Christian Flothmann <christian.flothmann@xabbuh.de> |
||||
* |
||||
* For the full copyright and license information, please view the LICENSE |
||||
* file that was distributed with this source code. |
||||
*/ |
||||
|
||||
namespace Chamilo\PluginBundle\Entity\XApi\Lrs; |
||||
|
||||
use Doctrine\ORM\Mapping as ORM; |
||||
use Xabbuh\XApi\Model\Statement as StatementModel; |
||||
use Xabbuh\XApi\Model\StatementId; |
||||
|
||||
/** |
||||
* A {@link Statement} mapped to a storage backend. |
||||
* |
||||
* @author Christian Flothmann <christian.flothmann@xabbuh.de> |
||||
* |
||||
* @ORM\Table(name="xapi_statement") |
||||
* @ORM\Entity() |
||||
*/ |
||||
class Statement |
||||
{ |
||||
/** |
||||
* @var string |
||||
* |
||||
* @ORM\Id() |
||||
* @ORM\GeneratedValue(strategy="NONE") |
||||
* @ORM\Column(type="string") |
||||
*/ |
||||
public $id; |
||||
|
||||
/** |
||||
* @var StatementObject |
||||
* |
||||
* @ORM\OneToOne(targetEntity="Chamilo\PluginBundle\Entity\XApi\Lrs\StatementObject", cascade={"ALL"}) |
||||
* @ORM\JoinColumn(referencedColumnName="identifier") |
||||
*/ |
||||
public $actor; |
||||
|
||||
/** |
||||
* @var Verb |
||||
* |
||||
* @ORM\OneToOne(targetEntity="Chamilo\PluginBundle\Entity\XApi\Lrs\Verb", cascade={"ALL"}) |
||||
* @ORM\JoinColumn(referencedColumnName="identifier") |
||||
*/ |
||||
public $verb; |
||||
|
||||
/** |
||||
* @var StatementObject |
||||
* |
||||
* @ORM\OneToOne(targetEntity="Chamilo\PluginBundle\Entity\XApi\Lrs\StatementObject", cascade={"ALL"}) |
||||
* @ORM\JoinColumn(referencedColumnName="identifier") |
||||
*/ |
||||
public $object; |
||||
|
||||
/** |
||||
* @var Result |
||||
* |
||||
* @ORM\OneToOne(targetEntity="Chamilo\PluginBundle\Entity\XApi\Lrs\Result", cascade={"ALL"}) |
||||
* @ORM\JoinColumn(referencedColumnName="identifier") |
||||
*/ |
||||
public $result; |
||||
|
||||
/** |
||||
* @var StatementObject |
||||
* |
||||
* @ORM\OneToOne(targetEntity="Chamilo\PluginBundle\Entity\XApi\Lrs\StatementObject", cascade={"ALL"}) |
||||
* @ORM\JoinColumn(referencedColumnName="identifier") |
||||
*/ |
||||
public $authority; |
||||
|
||||
/** |
||||
* @var int |
||||
* |
||||
* @ORM\Column(type="bigint", nullable=true) |
||||
*/ |
||||
public $created; |
||||
|
||||
/** |
||||
* @var int |
||||
* |
||||
* @ORM\Column(type="bigint", nullable=true) |
||||
*/ |
||||
public $stored; |
||||
|
||||
/** |
||||
* @var Context |
||||
* |
||||
* @ORM\OneToOne(targetEntity="Chamilo\PluginBundle\Entity\XApi\Lrs\Context", cascade={"ALL"}) |
||||
* @ORM\JoinColumn(referencedColumnName="identifier") |
||||
*/ |
||||
public $context; |
||||
|
||||
/** |
||||
* @var bool |
||||
* |
||||
* @ORM\Column(type="boolean", nullable=true) |
||||
*/ |
||||
public $hasAttachments; |
||||
|
||||
/** |
||||
* @var Attachment[]|null |
||||
* |
||||
* @ORM\OneToMany(targetEntity="Chamilo\PluginBundle\Entity\XApi\Lrs\Attachment", mappedBy="statement", cascade={"ALL"}) |
||||
*/ |
||||
public $attachments; |
||||
|
||||
/** |
||||
* @param \Xabbuh\XApi\Model\Statement $model |
||||
* |
||||
* @return \Chamilo\PluginBundle\Entity\XApi\Lrs\Statement |
||||
*/ |
||||
public static function fromModel(StatementModel $model) |
||||
{ |
||||
$statement = new self(); |
||||
$statement->id = $model->getId()->getValue(); |
||||
$statement->actor = StatementObject::fromModel($model->getActor()); |
||||
$statement->verb = Verb::fromModel($model->getVerb()); |
||||
$statement->object = StatementObject::fromModel($model->getObject()); |
||||
|
||||
if (null !== $model->getCreated()) { |
||||
$statement->created = $model->getCreated()->getTimestamp(); |
||||
} |
||||
|
||||
if (null !== $result = $model->getResult()) { |
||||
$statement->result = Result::fromModel($result); |
||||
} |
||||
|
||||
if (null !== $authority = $model->getAuthority()) { |
||||
$statement->authority = StatementObject::fromModel($authority); |
||||
} |
||||
|
||||
if (null !== $context = $model->getContext()) { |
||||
$statement->context = Context::fromModel($context); |
||||
} |
||||
|
||||
if (null !== $attachments = $model->getAttachments()) { |
||||
$statement->hasAttachments = true; |
||||
$statement->attachments = array(); |
||||
|
||||
foreach ($attachments as $attachment) { |
||||
$mappedAttachment = Attachment::fromModel($attachment); |
||||
$mappedAttachment->statement = $statement; |
||||
$statement->attachments[] = $mappedAttachment; |
||||
} |
||||
} else { |
||||
$statement->hasAttachments = false; |
||||
} |
||||
|
||||
return $statement; |
||||
} |
||||
|
||||
/** |
||||
* @throws \Exception |
||||
* @return \Xabbuh\XApi\Model\Statement |
||||
*/ |
||||
public function getModel() |
||||
{ |
||||
$result = null; |
||||
$authority = null; |
||||
$created = null; |
||||
$stored = null; |
||||
$context = null; |
||||
$attachments = null; |
||||
|
||||
if (null !== $this->result) { |
||||
$result = $this->result->getModel(); |
||||
} |
||||
|
||||
if (null !== $this->authority) { |
||||
$authority = $this->authority->getModel(); |
||||
} |
||||
|
||||
if (null !== $this->created) { |
||||
$created = new \DateTime('@'.$this->created); |
||||
} |
||||
|
||||
if (null !== $this->stored) { |
||||
$stored = new \DateTime('@'.$this->stored); |
||||
} |
||||
|
||||
if (null !== $this->context) { |
||||
$context = $this->context->getModel(); |
||||
} |
||||
|
||||
if ($this->hasAttachments) { |
||||
$attachments = array(); |
||||
|
||||
foreach ($this->attachments as $attachment) { |
||||
$attachments[] = $attachment->getModel(); |
||||
} |
||||
} |
||||
|
||||
return new StatementModel( |
||||
StatementId::fromString($this->id), |
||||
$this->actor->getModel(), |
||||
$this->verb->getModel(), |
||||
$this->object->getModel(), |
||||
$result, |
||||
$authority, |
||||
$created, |
||||
$stored, |
||||
$context, |
||||
$attachments |
||||
); |
||||
} |
||||
} |
||||
@ -1,496 +0,0 @@ |
||||
<?php |
||||
|
||||
/* |
||||
* This file is part of the xAPI package. |
||||
* |
||||
* (c) Christian Flothmann <christian.flothmann@xabbuh.de> |
||||
* |
||||
* For the full copyright and license information, please view the LICENSE |
||||
* file that was distributed with this source code. |
||||
*/ |
||||
|
||||
namespace Chamilo\PluginBundle\Entity\XApi\Lrs; |
||||
|
||||
use Doctrine\ORM\Mapping as ORM; |
||||
use Xabbuh\XApi\Model\Account; |
||||
use Xabbuh\XApi\Model\Activity; |
||||
use Xabbuh\XApi\Model\Actor as ActorModel; |
||||
use Xabbuh\XApi\Model\Agent; |
||||
use Xabbuh\XApi\Model\Definition; |
||||
use Xabbuh\XApi\Model\Group; |
||||
use Xabbuh\XApi\Model\InverseFunctionalIdentifier; |
||||
use Xabbuh\XApi\Model\IRI; |
||||
use Xabbuh\XApi\Model\IRL; |
||||
use Xabbuh\XApi\Model\LanguageMap; |
||||
use Xabbuh\XApi\Model\Object as ObjectModel; |
||||
use Xabbuh\XApi\Model\StatementObject as StatementObjectModel; |
||||
use Xabbuh\XApi\Model\StatementId; |
||||
use Xabbuh\XApi\Model\StatementReference; |
||||
use Xabbuh\XApi\Model\SubStatement; |
||||
|
||||
/** |
||||
* @author Christian Flothmann <christian.flothmann@xabbuh.de> |
||||
* |
||||
* @ORM\Table(name="xapi_object") |
||||
* @ORM\Entity() |
||||
*/ |
||||
class StatementObject |
||||
{ |
||||
const TYPE_ACTIVITY = 'activity'; |
||||
const TYPE_AGENT = 'agent'; |
||||
const TYPE_GROUP = 'group'; |
||||
const TYPE_STATEMENT_REFERENCE = 'statement_reference'; |
||||
const TYPE_SUB_STATEMENT = 'sub_statement'; |
||||
|
||||
/** |
||||
* @var int |
||||
* |
||||
* @ORM\Id() |
||||
* @ORM\GeneratedValue() |
||||
* @ORM\Column(type="integer") |
||||
*/ |
||||
public $identifier; |
||||
|
||||
/** |
||||
* @var string |
||||
* |
||||
* @ORM\Column(type="string", nullable=true) |
||||
*/ |
||||
public $type; |
||||
|
||||
/** |
||||
* @var string|null |
||||
* |
||||
* @ORM\Column(type="string", nullable=true) |
||||
*/ |
||||
public $activityId; |
||||
|
||||
/** |
||||
* @var bool|null |
||||
* |
||||
* @ORM\Column(type="boolean", nullable=true) |
||||
*/ |
||||
public $hasActivityDefinition; |
||||
|
||||
/** |
||||
* @var bool|null |
||||
* |
||||
* @ORM\Column(type="boolean", nullable=true) |
||||
*/ |
||||
public $hasActivityName; |
||||
|
||||
/** |
||||
* @var array|null |
||||
* |
||||
* @ORM\Column(type="json", nullable=true) |
||||
*/ |
||||
public $activityName; |
||||
|
||||
/** |
||||
* @var bool|null |
||||
* |
||||
* @ORM\Column(type="boolean", nullable=true) |
||||
*/ |
||||
public $hasActivityDescription; |
||||
|
||||
/** |
||||
* @var array|null |
||||
* |
||||
* @ORM\Column(type="json", nullable=true) |
||||
*/ |
||||
public $activityDescription; |
||||
|
||||
/** |
||||
* @var string|null |
||||
* |
||||
* @ORM\Column(type="string", nullable=true) |
||||
*/ |
||||
public $activityType; |
||||
|
||||
/** |
||||
* @var string|null |
||||
* |
||||
* @ORM\Column(type="string", nullable=true) |
||||
*/ |
||||
public $activityMoreInfo; |
||||
|
||||
/** |
||||
* @var Extensions|null |
||||
* |
||||
* @ORM\OneToOne(targetEntity="Chamilo\PluginBundle\Entity\XApi\Lrs\Extensions", cascade={"all"}) |
||||
* @ORM\JoinColumn(referencedColumnName="identifier") |
||||
*/ |
||||
public $activityExtensions; |
||||
|
||||
/** |
||||
* @var string|null |
||||
* |
||||
* @ORM\Column(type="string", nullable=true) |
||||
*/ |
||||
public $mbox; |
||||
|
||||
/** |
||||
* @var string|null |
||||
* |
||||
* @ORM\Column(type="string", nullable=true) |
||||
*/ |
||||
public $mboxSha1Sum; |
||||
|
||||
/** |
||||
* @var string|null |
||||
* |
||||
* @ORM\Column(type="string", nullable=true) |
||||
*/ |
||||
public $openId; |
||||
|
||||
/** |
||||
* @var string|null |
||||
* |
||||
* @ORM\Column(type="string", nullable=true) |
||||
*/ |
||||
public $accountName; |
||||
|
||||
/** |
||||
* @var string|null |
||||
* |
||||
* @ORM\Column(type="string", nullable=true) |
||||
*/ |
||||
public $accountHomePage; |
||||
|
||||
/** |
||||
* @var string|null |
||||
* |
||||
* @ORM\Column(type="string", nullable=true) |
||||
*/ |
||||
public $name; |
||||
|
||||
/** |
||||
* @var StatementObject[]|null |
||||
* |
||||
* @ORM\OneToMany(targetEntity="Chamilo\PluginBundle\Entity\XApi\Lrs\StatementObject", mappedBy="group") |
||||
*/ |
||||
public $members; |
||||
|
||||
/** |
||||
* @var StatementObject|null |
||||
* |
||||
* @ORM\ManyToOne(targetEntity="Chamilo\PluginBundle\Entity\XApi\Lrs\StatementObject", inversedBy="members") |
||||
* @ORM\JoinColumn(referencedColumnName="identifier") |
||||
*/ |
||||
public $group; |
||||
|
||||
/** |
||||
* @var string|null |
||||
* |
||||
* @ORM\Column(name="referenced_statement_id", type="string", nullable=true) |
||||
*/ |
||||
public $referencedStatementId; |
||||
|
||||
/** |
||||
* @var StatementObject|null |
||||
* |
||||
* @ORM\OneToOne(targetEntity="Chamilo\PluginBundle\Entity\XApi\Lrs\StatementObject", cascade={"ALL"}) |
||||
* @ORM\JoinColumn(referencedColumnName="identifier") |
||||
*/ |
||||
public $actor; |
||||
|
||||
/** |
||||
* @var Verb|null |
||||
* |
||||
* @ORM\OneToOne(targetEntity="Chamilo\PluginBundle\Entity\XApi\Lrs\Verb", cascade={"ALL"}) |
||||
* @ORM\JoinColumn(referencedColumnName="identifier") |
||||
*/ |
||||
public $verb; |
||||
|
||||
/** |
||||
* @var StatementObject|null |
||||
* |
||||
* @ORM\OneToOne(targetEntity="Chamilo\PluginBundle\Entity\XApi\Lrs\StatementObject", cascade={"ALL"}) |
||||
* @ORM\JoinColumn(referencedColumnName="identifier") |
||||
*/ |
||||
public $object; |
||||
|
||||
/** |
||||
* @var Result|null |
||||
*/ |
||||
public $result; |
||||
|
||||
/** |
||||
* @var Context|null |
||||
*/ |
||||
public $context; |
||||
|
||||
/** |
||||
* @var Statement|null |
||||
* |
||||
* @ORM\ManyToOne(targetEntity="Chamilo\PluginBundle\Entity\XApi\Lrs\Context", inversedBy="parentActivities") |
||||
* @ORM\JoinColumn(referencedColumnName="identifier") |
||||
*/ |
||||
public $parentContext; |
||||
|
||||
/** |
||||
* @var Statement|null |
||||
* |
||||
* @ORM\ManyToOne(targetEntity="Chamilo\PluginBundle\Entity\XApi\Lrs\Context", inversedBy="groupingActivities") |
||||
* @ORM\JoinColumn(referencedColumnName="identifier") |
||||
*/ |
||||
public $groupingContext; |
||||
|
||||
/** |
||||
* @var Statement|null |
||||
* |
||||
* @ORM\ManyToOne(targetEntity="Chamilo\PluginBundle\Entity\XApi\Lrs\Context", inversedBy="categoryActivities") |
||||
* @ORM\JoinColumn(referencedColumnName="identifier") |
||||
*/ |
||||
public $categoryContext; |
||||
|
||||
/** |
||||
* @var Statement|null |
||||
* |
||||
* @ORM\ManyToOne(targetEntity="Chamilo\PluginBundle\Entity\XApi\Lrs\Context", inversedBy="otherActivities") |
||||
* @ORM\JoinColumn(referencedColumnName="identifier") |
||||
*/ |
||||
public $otherContext; |
||||
|
||||
/** |
||||
* @param $model |
||||
* |
||||
* @return \Chamilo\PluginBundle\Entity\XApi\Lrs\StatementObject |
||||
*/ |
||||
public static function fromModel($model) |
||||
{ |
||||
if (!$model instanceof ObjectModel && !$model instanceof StatementObjectModel) { |
||||
throw new \InvalidArgumentException(sprintf('Expected a statement object but got %s', is_object($model) ? get_class($model) : gettype($model))); |
||||
} |
||||
|
||||
if ($model instanceof ActorModel) { |
||||
return self::fromActor($model); |
||||
} |
||||
|
||||
if ($model instanceof StatementReference) { |
||||
$object = new self(); |
||||
$object->type = self::TYPE_STATEMENT_REFERENCE; |
||||
$object->referencedStatementId = $model->getStatementId()->getValue(); |
||||
|
||||
return $object; |
||||
} |
||||
|
||||
if ($model instanceof SubStatement) { |
||||
return self::fromSubStatement($model); |
||||
} |
||||
|
||||
return self::fromActivity($model); |
||||
} |
||||
|
||||
/** |
||||
* @return \Xabbuh\XApi\Model\StatementObject |
||||
*/ |
||||
public function getModel() |
||||
{ |
||||
if (self::TYPE_AGENT === $this->type || self::TYPE_GROUP === $this->type) { |
||||
return $this->getActorModel(); |
||||
} |
||||
|
||||
if (self::TYPE_STATEMENT_REFERENCE === $this->type) { |
||||
return new StatementReference(StatementId::fromString($this->referencedStatementId)); |
||||
} |
||||
|
||||
if (self::TYPE_SUB_STATEMENT === $this->type) { |
||||
return $this->getSubStatementModel(); |
||||
} |
||||
|
||||
return $this->getActivityModel(); |
||||
} |
||||
|
||||
/** |
||||
* @param \Xabbuh\XApi\Model\Activity $model |
||||
* |
||||
* @return \Chamilo\PluginBundle\Entity\XApi\Lrs\StatementObject |
||||
*/ |
||||
private static function fromActivity(Activity $model) |
||||
{ |
||||
$object = new self(); |
||||
$object->activityId = $model->getId()->getValue(); |
||||
|
||||
if (null !== $definition = $model->getDefinition()) { |
||||
$object->hasActivityDefinition = true; |
||||
|
||||
if (null !== $name = $definition->getName()) { |
||||
$object->hasActivityName = true; |
||||
$object->activityName = array(); |
||||
|
||||
foreach ($name->languageTags() as $languageTag) { |
||||
$object->activityName[$languageTag] = $name[$languageTag]; |
||||
} |
||||
} else { |
||||
$object->hasActivityName = false; |
||||
} |
||||
|
||||
if (null !== $description = $definition->getDescription()) { |
||||
$object->hasActivityDescription = true; |
||||
$object->activityDescription = array(); |
||||
|
||||
foreach ($description->languageTags() as $languageTag) { |
||||
$object->activityDescription[$languageTag] = $description[$languageTag]; |
||||
} |
||||
} else { |
||||
$object->hasActivityDescription = false; |
||||
} |
||||
|
||||
if (null !== $type = $definition->getType()) { |
||||
$object->activityType = $type->getValue(); |
||||
} |
||||
|
||||
if (null !== $moreInfo = $definition->getMoreInfo()) { |
||||
$object->activityMoreInfo = $moreInfo->getValue(); |
||||
} |
||||
|
||||
if (null !== $extensions = $definition->getExtensions()) { |
||||
$object->activityExtensions = Extensions::fromModel($extensions); |
||||
} |
||||
} else { |
||||
$object->hasActivityDefinition = false; |
||||
} |
||||
|
||||
return $object; |
||||
} |
||||
|
||||
/** |
||||
* @param \Xabbuh\XApi\Model\Actor $model |
||||
* |
||||
* @return \Chamilo\PluginBundle\Entity\XApi\Lrs\StatementObject |
||||
*/ |
||||
private static function fromActor(ActorModel $model) |
||||
{ |
||||
$inverseFunctionalIdentifier = $model->getInverseFunctionalIdentifier(); |
||||
|
||||
$object = new self(); |
||||
$object->mboxSha1Sum = $inverseFunctionalIdentifier->getMboxSha1Sum(); |
||||
$object->openId = $inverseFunctionalIdentifier->getOpenId(); |
||||
|
||||
if (null !== $mbox = $inverseFunctionalIdentifier->getMbox()) { |
||||
$object->mbox = $mbox->getValue(); |
||||
} |
||||
|
||||
if (null !== $account = $inverseFunctionalIdentifier->getAccount()) { |
||||
$object->accountName = $account->getName(); |
||||
$object->accountHomePage = $account->getHomePage()->getValue(); |
||||
} |
||||
|
||||
if ($model instanceof Group) { |
||||
$object->type = self::TYPE_GROUP; |
||||
$object->members = array(); |
||||
|
||||
foreach ($model->getMembers() as $agent) { |
||||
$object->members[] = self::fromActor($agent); |
||||
} |
||||
} else { |
||||
$object->type = self::TYPE_AGENT; |
||||
} |
||||
|
||||
return $object; |
||||
} |
||||
|
||||
/** |
||||
* @param \Xabbuh\XApi\Model\SubStatement $model |
||||
* |
||||
* @return \Chamilo\PluginBundle\Entity\XApi\Lrs\StatementObject |
||||
*/ |
||||
private static function fromSubStatement(SubStatement $model) |
||||
{ |
||||
$object = new self(); |
||||
$object->type = self::TYPE_SUB_STATEMENT; |
||||
$object->actor = StatementObject::fromModel($model->getActor()); |
||||
$object->verb = Verb::fromModel($model->getVerb()); |
||||
$object->object = StatementObject::fromModel($model->getObject()); |
||||
|
||||
return $object; |
||||
} |
||||
|
||||
/** |
||||
* @return \Xabbuh\XApi\Model\Activity |
||||
*/ |
||||
private function getActivityModel() |
||||
{ |
||||
$definition = null; |
||||
$type = null; |
||||
$moreInfo = null; |
||||
|
||||
if ($this->hasActivityDefinition) { |
||||
$name = null; |
||||
$description = null; |
||||
$extensions = null; |
||||
|
||||
if ($this->hasActivityName) { |
||||
$name = LanguageMap::create($this->activityName); |
||||
} |
||||
|
||||
if ($this->hasActivityDescription) { |
||||
$description = LanguageMap::create($this->activityDescription); |
||||
} |
||||
|
||||
if (null !== $this->activityType) { |
||||
$type = IRI::fromString($this->activityType); |
||||
} |
||||
|
||||
if (null !== $this->activityMoreInfo) { |
||||
$moreInfo = IRL::fromString($this->activityMoreInfo); |
||||
} |
||||
|
||||
if (null !== $this->activityExtensions) { |
||||
$extensions = $this->activityExtensions->getModel(); |
||||
} |
||||
|
||||
$definition = new Definition($name, $description, $type, $moreInfo, $extensions); |
||||
} |
||||
|
||||
return new Activity(IRI::fromString($this->activityId), $definition); |
||||
} |
||||
|
||||
/** |
||||
* @return \Xabbuh\XApi\Model\Agent|\Xabbuh\XApi\Model\Group |
||||
*/ |
||||
private function getActorModel() |
||||
{ |
||||
$inverseFunctionalIdentifier = null; |
||||
|
||||
if (null !== $this->mbox) { |
||||
$inverseFunctionalIdentifier = InverseFunctionalIdentifier::withMbox(IRI::fromString($this->mbox)); |
||||
} elseif (null !== $this->mboxSha1Sum) { |
||||
$inverseFunctionalIdentifier = InverseFunctionalIdentifier::withMboxSha1Sum($this->mboxSha1Sum); |
||||
} elseif (null !== $this->openId) { |
||||
$inverseFunctionalIdentifier = InverseFunctionalIdentifier::withOpenId($this->openId); |
||||
} elseif (null !== $this->accountName && null !== $this->accountHomePage) { |
||||
$inverseFunctionalIdentifier = InverseFunctionalIdentifier::withAccount(new Account($this->accountName, IRL::fromString($this->accountHomePage))); |
||||
} |
||||
|
||||
if (self::TYPE_GROUP === $this->type) { |
||||
$members = array(); |
||||
|
||||
foreach ($this->members as $agent) { |
||||
$members[] = $agent->getModel(); |
||||
} |
||||
|
||||
return new Group($inverseFunctionalIdentifier, $this->name, $members); |
||||
} |
||||
|
||||
return new Agent($inverseFunctionalIdentifier, $this->name); |
||||
} |
||||
|
||||
/** |
||||
* @return \Xabbuh\XApi\Model\SubStatement |
||||
*/ |
||||
private function getSubStatementModel() |
||||
{ |
||||
$result = null; |
||||
$context = null; |
||||
|
||||
return new SubStatement( |
||||
$this->actor->getModel(), |
||||
$this->verb->getModel(), |
||||
$this->object->getModel(), |
||||
$result, |
||||
$context |
||||
); |
||||
} |
||||
} |
||||
@ -1,86 +0,0 @@ |
||||
<?php |
||||
|
||||
/* |
||||
* This file is part of the xAPI package. |
||||
* |
||||
* (c) Christian Flothmann <christian.flothmann@xabbuh.de> |
||||
* |
||||
* For the full copyright and license information, please view the LICENSE |
||||
* file that was distributed with this source code. |
||||
*/ |
||||
|
||||
namespace Chamilo\PluginBundle\Entity\XApi\Lrs; |
||||
|
||||
use Doctrine\ORM\Mapping as ORM; |
||||
use Xabbuh\XApi\Model\IRI; |
||||
use Xabbuh\XApi\Model\LanguageMap; |
||||
use Xabbuh\XApi\Model\Verb as VerbModel; |
||||
|
||||
/** |
||||
* A {@link Verb} mapped to a storage backend. |
||||
* |
||||
* @author Christian Flothmann <christian.flothmann@xabbuh.de> |
||||
* |
||||
* @ORM\Table(name="xapi_verb") |
||||
* @ORM\Entity() |
||||
*/ |
||||
class Verb |
||||
{ |
||||
/** |
||||
* @var int |
||||
* |
||||
* @ORM\Column(type="integer") |
||||
* @ORM\Id() |
||||
* @ORM\GeneratedValue() |
||||
*/ |
||||
public $identifier; |
||||
|
||||
/** |
||||
* @var string |
||||
* |
||||
* @ORM\Column(type="string") |
||||
*/ |
||||
public $id; |
||||
|
||||
/** |
||||
* @var array|null |
||||
* |
||||
* @ORM\Column(type="json") |
||||
*/ |
||||
public $display; |
||||
|
||||
/** |
||||
* @return \Xabbuh\XApi\Model\Verb |
||||
*/ |
||||
public function getModel() |
||||
{ |
||||
$display = null; |
||||
|
||||
if (null !== $this->display) { |
||||
$display = LanguageMap::create($this->display); |
||||
} |
||||
|
||||
return new VerbModel(IRI::fromString($this->id), $display); |
||||
} |
||||
|
||||
/** |
||||
* @param \Xabbuh\XApi\Model\Verb $model |
||||
* |
||||
* @return \Chamilo\PluginBundle\Entity\XApi\Lrs\Verb |
||||
*/ |
||||
public static function fromModel(VerbModel $model) |
||||
{ |
||||
$verb = new self(); |
||||
$verb->id = $model->getId()->getValue(); |
||||
|
||||
if (null !== $display = $model->getDisplay()) { |
||||
$verb->display = array(); |
||||
|
||||
foreach ($display->languageTags() as $languageTag) { |
||||
$verb->display[$languageTag] = $display[$languageTag]; |
||||
} |
||||
} |
||||
|
||||
return $verb; |
||||
} |
||||
} |
||||
Loading…
Reference in new issue