Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

This is just to talk about Dependency Injection #159

Closed
Closed
101 changes: 101 additions & 0 deletions services/CollectionService/src/Controller/CollectionController.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
<?php

namespace Islandora\CollectionService\Controller;

use Silex\Application;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;

class CollectionController {

protected $uuidGenerator;

public function __construct(IUuidGenerator $uuidGenerator) {
$this->uuidGenerator = $uuidGenerator;
}

public function create(Application $app, Request $request, $id) {
$tx = $request->query->get('tx', "");

//Check for format
$format = NULL;
try {
$format = \EasyRdf_Format::getFormat($contentType = $request->headers->get('Content-Type', 'text/turtle'));
} catch (\EasyRdf_Exception $e) {
$app->abort(415, $e->getMessage());
}

//Now check if body can be parsed in that format
if ($format) { //EasyRdf_Format
//@see http://www.w3.org/2011/rdfa-context/rdfa-1.1 for defaults
\EasyRdf_Namespace::set('pcdm', 'http://pcdm.org/models#');
\EasyRdf_Namespace::set('nfo', 'http://www.semanticdesktop.org/ontologies/2007/03/22/nfo/v1.1/');
\EasyRdf_Namespace::set('isl', 'http://www.islandora.ca/ontologies/2016/02/28/isl/v1.0/');
\EasyRdf_Namespace::set('ldp', 'http://www.w3.org/ns/ldp');

//Fake IRI, default LDP one for current resource "<>" is not a valid IRI!
$fakeUuid = $uuidGenerator->generateV5("derp");
$fakeIri = new \EasyRdf_ParsedUri('urn:uuid:' . $fakeUuid);

$graph = new \EasyRdf_Graph();
try {
$graph->parse($request->getContent(), $format->getName(), $fakeIri);
} catch (\EasyRdf_Exception $e) {
$app->abort(415, $e->getMessage());
}
//Add a pcmd:Collection type
$graph->resource($fakeIri, 'pcdm:Collection');

//Check if we got an UUID inside posted RDF. We won't validate it here because it's the caller responsability
if (NULL != $graph->countValues($fakeIri, '<http://www.semanticdesktop.org/ontologies/2007/03/22/nfo/v1.1/uuid>')) {
$existingUuid = $graph->getLiteral($fakeIri, '<http://www.semanticdesktop.org/ontologies/2007/03/22/nfo/v1.1/uuid>');
$graph->addResource($fakeIri, 'http://www.islandora.ca/ontologies/2016/02/28/isl/v1.0/hasURN', 'urn:uuid:'.$existingUuid); //Testing an Islandora Ontology!
} else {
//No UUID from the caller in RDF, lets put something there
$graph->addLiteral($fakeIri,"http://www.semanticdesktop.org/ontologies/2007/03/22/nfo/v1.1/uuid",$fakeUuid); //Keeps compat for now with other services
$graph->addResource($fakeIri,"http://www.islandora.ca/ontologies/2016/02/28/isl/v1.0/hasURN",'urn:uuid:'.$fakeUuid); //Testing an Islandora Ontology
}
//Restore LDP <> IRI on serialised graph
$pcmd_collection_rdf= str_replace($fakeIri, '', $graph->serialise('turtle'));
}

$urlRoute = $request->getUriForPath('/islandora/resource/');

$subRequestPost = Request::create($urlRoute.$id, 'POST', array(), $request->cookies->all(), array(), $request->server->all(), $pcmd_collection_rdf);
$subRequestPost->query->set('tx', $tx);
$subRequestPost->headers->set('Content-Type', 'text/turtle');
$responsePost = $app->handle($subRequestPost, HttpKernelInterface::SUB_REQUEST, false);

if (201 == $responsePost->getStatusCode()) {// OK, collection created
//Lets take the location header in the response
$indirect_container_rdf = $app['twig']->render('createIndirectContainerfromTS.ttl', array(
'resource' => $responsePost->headers->get('location'),
));

$subRequestPut = Request::create($urlRoute.$id, 'PUT', array(), $request->cookies->all(), array(), $request->server->all(), $indirect_container_rdf);
$subRequestPut->query->set('tx', $tx);
$subRequestPut->headers->set('Slug', 'members');
//Can't use in middleware, but needed. Without Fedora 4 throws big java errors!
$subRequestPut->headers->set('Host', $app['config']['islandora']['fedoraHost'], TRUE);
$subRequestPut->headers->set('Content-Type', 'text/turtle');
//Here is the thing. We don't know if UUID of the collection we just created is already in the tripple store.
//So what to do? We could just try to use our routes directly, but UUID check agains triplestore we could fail!
//lets invoke the controller method directly
$responsePut = $app['islandora.resourcecontroller']->put($app, $subRequestPut, $responsePost->headers->get('location'), "members");
if (201 == $responsePut->getStatusCode()) {// OK, indirect container created
//Include headers from the parent one, some of the last one. Basically rewrite everything
$putHeaders = $responsePut->getHeaders();
//Guzzle psr7 response objects are inmutable. So we have to make this an array and add directly
$putHeaders['Link'] = array('<'.$responsePut->getBody().'>; rel="alternate"');
$putHeaders['Link'] = array('<'.$urlRoute.$fakeUuid.'/members>; rel="hub"');
$putHeaders['Location'] = array($urlRoute.$fakeUuid);
//Should i care about the etag?
return new Response($putHeaders['Location'][0], 201, $putHeaders);
}

return $responsePut;
}
//Abort if PCDM collection object could not be created
$app->abort($responsePost->getStatusCode(), 'Failed creating PCDM Collection');
}
}
112 changes: 6 additions & 106 deletions services/CollectionService/src/index.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
require_once __DIR__.'/../vendor/autoload.php';

use Silex\Application;
use Islandora\Chullo\Uuid\UuidGenerator;
use Islandora\ResourceService\Provider\ResourceServiceProvider;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\Request;
Expand All @@ -22,23 +23,12 @@
'twig.path' => __DIR__.'/../templates',
));

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, some how lost here. How does the collection.controller makes use of the resource routes without having them registered or mounted? Who is mounting them? Thanks!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's totally non-functional. Was just trying to make a point about injecting things in and making sure to use PHP's type system for guarantees. I've yet to pull out the rest of the Resource Service stuff.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, right! Well sorry for being so silly. Thanks! I will go inject myself 👍

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LOL, no worries.

$islandoraResourceServiceProvider = new \Islandora\ResourceService\Provider\ResourceServiceProvider;

//Registers Resource Service and defines current app's path for config context
$app->register($islandoraResourceServiceProvider, array(
'islandora.BasePath' => __DIR__,
));
$app->mount("/islandora", $islandoraResourceServiceProvider);
$app->register(new \Islandora\ResourceService\Provider\UuidServiceProvider(), array(
'UuidServiceProvider.default_namespace' => $app['config']['islandora']['defaultNamespaceDomainUuuidV5'],
));

//We will use a static uuid5 to fake a real IRI to replace <> during turtle parsing
$app['uuid5'] = $app->share(function () use ($app) {
return $app['islandora.uuid5']($app['config']['islandora']['fedoraProtocol'].'://'.$app['config']['islandora']['fedoraHost'].$app['config']['islandora']['fedoraPath']);
$app['collection.controller'] = $app->share(function() {
return new CollectionController(new UuidGenerator());
});
//This is the uuidV4 generator
$app['uuid'] = $app['islandora.uuid4'];

$app->post("/islandora/collection/{id}", "collection.controller:create")
->value('id',"");

/**
* Convert returned Guzzle responses to Symfony responses.
Expand All @@ -48,96 +38,6 @@
return new Response($psr7->getBody(), $psr7->getStatusCode(), $psr7->getHeaders());
});

/**
* Collection POST route.
* Takes $id (valid UUID or empty) for the parent resource as first value to match,
* and also takes 'rx' as an optional query argument.
*/
$app->post("/islandora/collection/{id}", function (Request $request, $id) use ($app) {
$tx = $request->query->get('tx', "");

//Check for format
$format = NULL;
try {
$format = \EasyRdf_Format::getFormat($contentType = $request->headers->get('Content-Type', 'text/turtle'));
} catch (\EasyRdf_Exception $e) {
$app->abort(415, $e->getMessage());
}

//Now check if body can be parsed in that format
if ($format) { //EasyRdf_Format
//@see http://www.w3.org/2011/rdfa-context/rdfa-1.1 for defaults
\EasyRdf_Namespace::set('pcdm', 'http://pcdm.org/models#');
\EasyRdf_Namespace::set('nfo', 'http://www.semanticdesktop.org/ontologies/2007/03/22/nfo/v1.1/');
\EasyRdf_Namespace::set('isl', 'http://www.islandora.ca/ontologies/2016/02/28/isl/v1.0/');
\EasyRdf_Namespace::set('ldp', 'http://www.w3.org/ns/ldp');

//Fake IRI, default LDP one for current resource "<>" is not a valid IRI!
$fakeIri = new \EasyRdf_ParsedUri('urn:uuid:'.$app['uuid5']);

$graph = new \EasyRdf_Graph();
try {
$graph->parse($request->getContent(), $format->getName(), $fakeIri);
} catch (\EasyRdf_Exception $e) {
$app->abort(415, $e->getMessage());
}
//Add a pcmd:Collection type
$graph->resource($fakeIri, 'pcdm:Collection');

//Check if we got an UUID inside posted RDF. We won't validate it here because it's the caller responsability
if (NULL != $graph->countValues($fakeIri, '<http://www.semanticdesktop.org/ontologies/2007/03/22/nfo/v1.1/uuid>')) {
$existingUuid = $graph->getLiteral($fakeIri, '<http://www.semanticdesktop.org/ontologies/2007/03/22/nfo/v1.1/uuid>');
$graph->addResource($fakeIri, 'http://www.islandora.ca/ontologies/2016/02/28/isl/v1.0/hasURN', 'urn:uuid:'.$existingUuid); //Testing an Islandora Ontology!
} else {
//No UUID from the caller in RDF, lets put something there
$tmpUuid = $app['uuid']; //caching here, since it's regenerated each time it is used and I need the same twice
$graph->addLiteral($fakeIri,"http://www.semanticdesktop.org/ontologies/2007/03/22/nfo/v1.1/uuid",$tmpUuid); //Keeps compat for now with other services
$graph->addResource($fakeIri,"http://www.islandora.ca/ontologies/2016/02/28/isl/v1.0/hasURN",'urn:uuid:'.$tmpUuid); //Testing an Islandora Ontology
}
//Restore LDP <> IRI on serialised graph
$pcmd_collection_rdf= str_replace($fakeIri, '', $graph->serialise('turtle'));
}

$urlRoute = $request->getUriForPath('/islandora/resource/');

$subRequestPost = Request::create($urlRoute.$id, 'POST', array(), $request->cookies->all(), array(), $request->server->all(), $pcmd_collection_rdf);
$subRequestPost->query->set('tx', $tx);
$subRequestPost->headers->set('Content-Type', 'text/turtle');
$responsePost = $app->handle($subRequestPost, HttpKernelInterface::SUB_REQUEST, false);

if (201 == $responsePost->getStatusCode()) {// OK, collection created
//Lets take the location header in the response
$indirect_container_rdf = $app['twig']->render('createIndirectContainerfromTS.ttl', array(
'resource' => $responsePost->headers->get('location'),
));

$subRequestPut = Request::create($urlRoute.$id, 'PUT', array(), $request->cookies->all(), array(), $request->server->all(), $indirect_container_rdf);
$subRequestPut->query->set('tx', $tx);
$subRequestPut->headers->set('Slug', 'members');
//Can't use in middleware, but needed. Without Fedora 4 throws big java errors!
$subRequestPut->headers->set('Host', $app['config']['islandora']['fedoraHost'], TRUE);
$subRequestPut->headers->set('Content-Type', 'text/turtle');
//Here is the thing. We don't know if UUID of the collection we just created is already in the tripple store.
//So what to do? We could just try to use our routes directly, but UUID check agains triplestore we could fail!
//lets invoke the controller method directly
$responsePut = $app['islandora.resourcecontroller']->put($app, $subRequestPut, $responsePost->headers->get('location'), "members");
if (201 == $responsePut->getStatusCode()) {// OK, indirect container created
//Include headers from the parent one, some of the last one. Basically rewrite everything
$putHeaders = $responsePut->getHeaders();
//Guzzle psr7 response objects are inmutable. So we have to make this an array and add directly
$putHeaders['Link'] = array('<'.$responsePut->getBody().'>; rel="alternate"');
$putHeaders['Link'] = array('<'.$urlRoute.$tmpUuid.'/members>; rel="hub"');
$putHeaders['Location'] = array($urlRoute.$tmpUuid);
//Should i care about the etag?
return new Response($putHeaders['Location'][0], 201, $putHeaders);
}

return $responsePut;
}
//Abort if PCDM collection object could not be created
$app->abort($responsePost->getStatusCode(), 'Failed creating PCDM Collection');
})
->value('id',"");

$app->after(function (Request $request, Response $response) use ($app) {
$response->headers->set('X-Powered-By', 'Islandora Collection REST API v'.$app['config']['islandora']['apiVersion'], TRUE); //Nice
Expand Down
Loading