Commit 4d2bae16 authored by François Agneray's avatar François Agneray
Browse files

Adding Instance into metamodel

parent 82c73049
......@@ -65,4 +65,4 @@ dev-meta:
@docker-compose exec php sh ./conf-dev/dev-meta.sh
remove-pgdata:
@docker volume rm anis-metamodel_pgdata
@docker volume rm anis-server_pgdata
......@@ -22,6 +22,8 @@ $app->map([OPTIONS, GET, POST], '/family/{type}', App\Action\FamilyListAction::c
$app->map([OPTIONS, GET, PUT, DELETE], '/family/{type}/{id}', App\Action\FamilyAction::class);
$app->map([OPTIONS, GET, POST], '/output-category', App\Action\OutputCategoryListAction::class);
$app->map([OPTIONS, GET, PUT, DELETE], '/output-category/{id}', App\Action\OutputCategoryAction::class);
$app->map([OPTIONS, GET, POST], '/instance', App\Action\InstanceListAction::class);
$app->map([OPTIONS, GET, PUT, DELETE], '/instance/{name}', App\Action\InstanceAction::class);
$app->map([OPTIONS, GET, POST], '/dataset', App\Action\DatasetListAction::class);
$app->map([OPTIONS, GET, PUT, DELETE], '/dataset/{name}', App\Action\DatasetAction::class);
$app->map([OPTIONS, GET], '/dataset/{name}/attribute', App\Action\AttributeListAction::class);
......
......@@ -19,6 +19,7 @@ use Doctrine\ORM\EntityManagerInterface;
use App\Utils\DBALConnectionFactory;
use App\Entity\Database;
use App\Entity\Project;
use App\Entity\Instance;
use App\Entity\DatasetFamily;
use App\Entity\Dataset;
use App\Entity\Attribute;
......@@ -75,6 +76,7 @@ final class DatasetListAction extends AbstractAction
'data_path',
'selectable_row',
'project_name',
'instance_name',
'id_dataset_family'
);
foreach ($fields as $a) {
......@@ -95,6 +97,15 @@ final class DatasetListAction extends AbstractAction
);
}
// Instance is mandatory to add a new dataset
$instance = $this->em->find('App\Entity\Instance', $parsedBody['instance_name']);
if (is_null($instance)) {
throw new HttpBadRequestException(
$request,
'Instance with name ' . $parsedBody['instance_name'] . ' is not found'
);
}
$family = $this->em->find('App\Entity\DatasetFamily', $parsedBody['id_dataset_family']);
if (is_null($family)) {
throw new HttpBadRequestException(
......@@ -103,7 +114,7 @@ final class DatasetListAction extends AbstractAction
);
}
$dataset = $this->postDataset($parsedBody, $project, $family);
$dataset = $this->postDataset($parsedBody, $project, $instance, $family);
$payload = json_encode($dataset);
$response = $response->withStatus(201);
}
......@@ -121,8 +132,12 @@ final class DatasetListAction extends AbstractAction
*
* @return Dataset
*/
private function postDataset(array $parsedBody, Project $project, DatasetFamily $family): Dataset
{
private function postDataset(
array $parsedBody,
Project $project,
Instance $instance,
DatasetFamily $family
): Dataset {
$dataset = new Dataset($parsedBody['name']);
$dataset->setTableRef($parsedBody['table_ref']);
$dataset->setLabel($parsedBody['label']);
......@@ -133,6 +148,7 @@ final class DatasetListAction extends AbstractAction
$dataset->setDataPath($parsedBody['data_path']);
$dataset->setSelectableRow($parsedBody['selectable_row']);
$dataset->setProject($project);
$dataset->setInstance($instance);
$dataset->setDatasetFamily($family);
$this->em->persist($dataset);
......
<?php
/*
* This file is part of Anis Server.
*
* (c) Laboratoire d'Astrophysique de Marseille / CNRS
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
declare(strict_types=1);
namespace App\Action;
use Psr\Http\Message\ServerRequestInterface as Request;
use Psr\Http\Message\ResponseInterface as Response;
use Slim\Exception\HttpBadRequestException;
use Slim\Exception\HttpNotFoundException;
use App\Entity\Instance;
final class InstanceAction extends AbstractAction
{
/**
* `GET` Returns the instance found
* `PUT` Full update the instance and returns the new version
* `DELETE` Delete the instance found and return a confirmation message
*
* @param ServerRequestInterface $request PSR-7 This object represents the HTTP request
* @param ResponseInterface $response PSR-7 This object represents the HTTP response
* @param string[] $args This table contains information transmitted in the URL (see routes.php)
*
* @return ResponseInterface
*/
public function __invoke(Request $request, Response $response, array $args): Response
{
if ($request->getMethod() === OPTIONS) {
return $response->withHeader('Access-Control-Allow-Methods', 'GET, PUT, DELETE, OPTIONS');
}
// Search the correct instance with primary key
$instance = $this->em->find('App\Entity\Instance', $args['name']);
// If instance is not found 404
if (is_null($instance)) {
throw new HttpNotFoundException(
$request,
'Instance with name ' . $args['name'] . ' is not found'
);
}
if ($request->getMethod() === GET) {
$payload = json_encode($instance);
}
if ($request->getMethod() === PUT) {
$parsedBody = $request->getParsedBody();
// If mandatories empty fields 400
foreach (array('label', 'client_url') as $a) {
if ($this->isEmptyField($a, $parsedBody)) {
throw new HttpBadRequestException(
$request,
'Param ' . $a . ' needed to edit the instance'
);
}
}
$this->editInstance($instance, $parsedBody);
$payload = json_encode($instance);
}
if ($request->getMethod() === DELETE) {
$name = $instance->getName();
$this->em->remove($instance);
$this->em->flush();
$payload = json_encode(array('message' => 'Instance with name ' . $name . ' is removed!'));
}
$response->getBody()->write($payload);
return $response;
}
/**
* Update instance object with setters
*
* @param Instance $instance The instance to update
* @param array $parsedBody Contains the new values ​​of the instance sent by the user
*/
private function editInstance(Instance $instance, array $parsedBody): void
{
$instance->setLabel($parsedBody['label']);
$instance->setClientUrl($parsedBody['client_url']);
$this->em->flush();
}
}
<?php
/*
* This file is part of Anis Server.
*
* (c) Laboratoire d'Astrophysique de Marseille / CNRS
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
declare(strict_types=1);
namespace App\Action;
use Psr\Http\Message\ServerRequestInterface as Request;
use Psr\Http\Message\ResponseInterface as Response;
use Slim\Exception\HttpBadRequestException;
use App\Entity\Instance;
final class InstanceListAction extends AbstractAction
{
/**
* `GET` Returns a list of all instances listed in the metamodel
* `POST` Add a new instance
*
* @param ServerRequestInterface $request PSR-7 This object represents the HTTP request
* @param ResponseInterface $response PSR-7 This object represents the HTTP response
* @param string[] $args This table contains information transmitted in the URL (see routes.php)
*
* @return ResponseInterface
*/
public function __invoke(Request $request, Response $response, array $args): Response
{
if ($request->getMethod() === OPTIONS) {
return $response->withHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS');
}
if ($request->getMethod() === GET) {
// Retrieve user with email adress
$instances = $this->em->getRepository('App\Entity\Instance')->findAll();
$payload = json_encode($instances);
}
if ($request->getMethod() === POST) {
$parsedBody = $request->getParsedBody();
// To work this action needs user information to update
foreach (array('name', 'label', 'client_url') as $a) {
if ($this->isEmptyField($a, $parsedBody)) {
throw new HttpBadRequestException(
$request,
'Param ' . $a . ' needed to add a new instance'
);
}
}
$instance = $this->postInstance($parsedBody);
$payload = json_encode($instance);
$response = $response->withStatus(201);
}
$response->getBody()->write($payload);
return $response;
}
/**
* Add a new instance into the metamodel
*
* @param array $parsedBody Contains the values ​​of the new instance sent by the user
*/
private function postInstance(array $parsedBody): Instance
{
$instance = new Instance($parsedBody['name'], $parsedBody['label']);
$instance->setClientUrl($parsedBody['client_url']);
$this->em->persist($instance);
$this->em->flush();
return $instance;
}
}
......@@ -92,6 +92,14 @@ class Dataset implements \JsonSerializable
*/
protected $project;
/**
* @var Anis\Entity\Instance
*
* @ManyToOne(targetEntity="Instance")
* @JoinColumn(name="instance_name", referencedColumnName="name", nullable=false)
*/
protected $instance;
/**
* @var Anis\Entity\Project
*
......@@ -222,6 +230,16 @@ class Dataset implements \JsonSerializable
$this->project = $project;
}
public function getInstance(): Instance
{
return $this->instance;
}
public function setInstance(Instance $instance): void
{
$this->instance = $instance;
}
public function getDatasetFamily()
{
return $this->datasetFamily;
......@@ -265,6 +283,7 @@ class Dataset implements \JsonSerializable
'data_path' => $this->getDataPath(),
'selectable_row' => $this->getSelectableRow(),
'project_name' => $this->getProject()->getName(),
'instance_name' => $this->getInstance()->getName(),
'id_dataset_family' => $this->getDatasetFamily()->getId()
];
}
......
<?php
/*
* This file is part of Anis Server.
*
* (c) Laboratoire d'Astrophysique de Marseille / CNRS
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
declare(strict_types=1);
namespace App\Entity;
/**
* @Entity
* @Table(name="instance")
*/
class Instance implements \JsonSerializable
{
/**
* @var integer
*
* @Id
* @Column(type="string", nullable=false)
*/
protected $name;
/**
* @var string
*
* @Column(type="string", nullable=false)
*/
protected $label;
/**
* @var string
*
* @Column(type="string", nullable=true)
*/
protected $clientUrl;
public function __construct(string $name, string $label)
{
$this->name = $name;
$this->label = $label;
}
public function getName(): string
{
return $this->name;
}
public function getLabel(): string
{
return $this->label;
}
public function setLabel(string $label): void
{
$this->label = $label;
}
public function getClientUrl(): string
{
return $this->clientUrl;
}
public function setClientUrl($clientUrl): void
{
$this->clientUrl = $clientUrl;
}
public function jsonSerialize()
{
return [
'name' => $this->getName(),
'label' => $this->getLabel(),
'client_url' => $this->getClientUrl()
];
}
}
......@@ -20,6 +20,7 @@ use Slim\Exception\HttpBadRequestException;
use App\tests\EntityManagerBuilder;
use App\Entity\Database;
use App\Entity\Project;
use App\Entity\Instance;
use App\Entity\DatasetFamily;
use App\Entity\CriteriaFamily;
use App\Entity\OutputFamily;
......@@ -161,6 +162,15 @@ final class AttributeActionTest extends TestCase
return $project;
}
private function addInstance(): Instance
{
$instance = new Instance('aspic', 'Aspic');
$instance->setClientUrl('http://cesam.lam.fr/aspic');
$this->entityManager->persist($instance);
$this->entityManager->flush();
return $instance;
}
private function addDatasetFamily(): DatasetFamily
{
$family = new DatasetFamily();
......@@ -208,6 +218,7 @@ final class AttributeActionTest extends TestCase
private function addADataset(): Dataset
{
$project = $this->addProject();
$instance = $this->addInstance();
$family = $this->addDatasetFamily();
$dataset = new Dataset('obs_cat');
......@@ -220,6 +231,7 @@ final class AttributeActionTest extends TestCase
$dataset->setDataPath('/mnt/obs_cat');
$dataset->setSelectableRow(false);
$dataset->setProject($project);
$dataset->setInstance($instance);
$dataset->setDatasetFamily($family);
$this->entityManager->persist($dataset);
$this->entityManager->flush();
......
......@@ -20,6 +20,7 @@ use Slim\Exception\HttpNotFoundException;
use App\tests\EntityManagerBuilder;
use App\Entity\Database;
use App\Entity\Project;
use App\Entity\Instance;
use App\Entity\DatasetFamily;
use App\Entity\Dataset;
use App\Entity\Attribute;
......@@ -97,6 +98,15 @@ final class AttributeListActionTest extends TestCase
return $project;
}
private function addInstance(): Instance
{
$instance = new Instance('aspic', 'Aspic');
$instance->setClientUrl('http://cesam.lam.fr/aspic');
$this->entityManager->persist($instance);
$this->entityManager->flush();
return $instance;
}
private function addDatasetFamily(): DatasetFamily
{
$family = new DatasetFamily();
......@@ -110,6 +120,7 @@ final class AttributeListActionTest extends TestCase
private function addADataset(): Dataset
{
$project = $this->addProject();
$instance = $this->addInstance();
$family = $this->addDatasetFamily();
$dataset = new Dataset('obs_cat');
......@@ -122,6 +133,7 @@ final class AttributeListActionTest extends TestCase
$dataset->setDataPath('/mnt/obs_cat');
$dataset->setSelectableRow(false);
$dataset->setProject($project);
$dataset->setInstance($instance);
$dataset->setDatasetFamily($family);
$this->entityManager->persist($dataset);
$this->entityManager->flush();
......
......@@ -20,6 +20,7 @@ use Slim\Exception\HttpBadRequestException;
use App\tests\EntityManagerBuilder;
use App\Entity\Database;
use App\Entity\Project;
use App\Entity\Instance;
use App\Entity\DatasetFamily;
use App\Entity\Dataset;
......@@ -92,7 +93,7 @@ final class DatasetActionTest extends TestCase
array_merge(
['name' => 'obs_cat', 'table_ref' => 'v_obs_cat'],
$fields,
['project_name' => 'anis_project', 'id_dataset_family' => 1]
['project_name' => 'anis_project', 'instance_name' => 'aspic', 'id_dataset_family' => 1]
),
JSON_UNESCAPED_SLASHES
),
......@@ -101,7 +102,7 @@ final class DatasetActionTest extends TestCase
$this->assertEquals(200, (int) $response->getStatusCode());
}
public function testDeleteADatabase(): void
public function testDeleteADataset(): void
{
$this->addADataset();
$request = $this->getRequest('DELETE');
......@@ -162,6 +163,15 @@ final class DatasetActionTest extends TestCase
return $project;
}
private function addInstance(): Instance
{
$instance = new Instance('aspic', 'Aspic');
$instance->setClientUrl('http://cesam.lam.fr/aspic');
$this->entityManager->persist($instance);
$this->entityManager->flush();
return $instance;
}
private function addDatasetFamily(): DatasetFamily
{
$family = new DatasetFamily();
......@@ -176,6 +186,7 @@ final class DatasetActionTest extends TestCase
private function addADataset(): Dataset
{
$project = $this->addProject();
$instance = $this->addInstance();
$family = $this->addDatasetFamily();
$dataset = new Dataset('obs_cat');
......@@ -188,6 +199,7 @@ final class DatasetActionTest extends TestCase
$dataset->setDataPath('/mnt/obs_cat');
$dataset->setSelectableRow(false);
$dataset->setProject($project);
$dataset->setInstance($instance);
$dataset->setDatasetFamily($family);
$this->entityManager->persist($dataset);
$this->entityManager->flush();
......
......@@ -24,6 +24,7 @@ use Doctrine\DBAL\Types\Type;
use App\tests\EntityManagerBuilder;
use App\Entity\Database;
use App\Entity\Project;
use App\Entity\Instance;
use App\Entity\DatasetFamily;
use App\Entity\Dataset;
......@@ -78,6 +79,7 @@ final class DatasetListActionTest extends TestCase
public function testAddANewDatasetFamilyNotFound(): void
{
$this->addProject();
$this->addInstance();
$this->expectException(HttpBadRequestException::class);
$this->expectExceptionMessage('Dataset family with id 1 is not found');
$fields = $this->getNewDatasetFields();
......@@ -86,9 +88,21 @@ final class DatasetListActionTest extends TestCase
$this->assertEquals(400, (int) $response->getStatusCode());
}
public function testAddANewDatasetInstanceNotFound(): void
{
$this->addProject();
$this->expectException(HttpBadRequestException::class);
$this->expectExceptionMessage('Instance with name aspic is not found');
$fields = $this->getNewDatasetFields();
$request = $this->getRequest('POST')->withParsedBody($fields);
$response = ($this->action)($request, new Response(), array());
$this->assertEquals(400, (int) $response->getStatusCode());
}
public function testAddANewDataset(): void
{
$this->addProject();
$this->addInstance();
$this->addDatasetFamily();
$fields = $this->getNewDatasetFields();
$request = $this->getRequest('POST')->withParsedBody($fields);
......@@ -125,6 +139,7 @@ final class DatasetListActionTest extends TestCase
'data_path' => '/mnt/dataset1',
'selectable_row' => false,
'project_name' => 'anis_project',
'instance_name' => 'aspic',
'id_dataset_family' => 1
);
}
......@@ -153,6 +168,15 @@ final class DatasetListActionTest extends TestCase
return $project;
}
private function addInstance(): Instance
{
$instance = new Instance('aspic', 'Aspic');
$instance->setClientUrl('http://cesam.lam.fr/aspic');
$this->entityManager->persist($instance);
$this->entityManager->flush();
return $instance;
}
private function addDatasetFamily(): DatasetFamily
{
$family = new DatasetFamily();
......@@ -167,6 +191,7 @@ final class DatasetListActionTest extends TestCase
private function addDatasets(): array
{
$project = $this->addProject();
$instance = $this->addInstance();
$family = $this->addDatasetFamily();
$dataset1 = new Dataset('dataset1');
......@@ -179,6 +204,7 @@ final class DatasetListActionTest extends TestCase
$dataset1->setDataPath('/mnt/dataset1');
$dataset1->setSelectableRow(false);
$dataset1->setProject($project);
$dataset1->setInstance($instance);
$dataset1->setDatasetFamily($family);
$this->entityManager->persist($dataset1);
......@@ -192,6 +218,7 @@ final class DatasetListActionTest extends TestCase
$dataset2->setDataPath('/mnt/dataset2');
$dataset2->setSelectableRow(false);
$dataset2->setProject($project);
$dataset2->setInstance($instance);
$dataset2->setDatasetFamily($family);
$this->entityManager->persist($dataset2);
......
<?php
/*
* This file is part of Anis Server.
*
* (c) Laboratoire d'Astrophysique de Marseille / CNRS
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
declare(strict_types=1);
namespace App\Tests\Action;
use PHPUnit\Framework\TestCase;
use Nyholm\Psr7\ServerRequest;
use Nyholm\Psr7\Response;
use Slim\Exception\HttpNotFoundException;
use Slim\Exception\HttpBadRequestException;
use App\tests\EntityManagerBuilder;
use App\Entity\Instance;
final class InstanceActionTest extends TestCase
{
private $action;