Skip to content

Commit

Permalink
Add Scope, Cardinality, Type, and DictionaryItem classes
Browse files Browse the repository at this point in the history
This adds the classes representing the data scope, data type,
data cardinality, DictionaryItem (and dictionary Category) from
PR #6936 but does not use yet use them.
  • Loading branch information
driusan committed Aug 27, 2020
1 parent a87ead0 commit 20bf05b
Show file tree
Hide file tree
Showing 6 changed files with 388 additions and 1 deletion.
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ changes in the following format: PR #1234***

##LORIS 24.0 (Release Date: ??)
### Core
- New classes to describe a data dictionary (PR #6938)
#### Features
- *Add item here*
#### Updates and Improvements
Expand Down Expand Up @@ -118,4 +119,4 @@ be used by projects having custom modules not in LORIS. (PR #5913)
- The tool `phpstan` has been added to our automated test suite. (PR #4928)
- Config files for static analysis have been moved to the `test/` directory. (PR #5871)
- Dashboard was refactored to turn panels into module widgets. (PR #5896)
- Add CSSGrid component type (PR #6090)
- Add CSSGrid component type (PR #6090)
100 changes: 100 additions & 0 deletions src/Data/Cardinality.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
<?php
namespace LORIS\Data;

/**
* Cardinality represents the number of data points which
* apply to the scope of a data type.
*
* Since the Cardinality class represents an enumeration, the
* class is final.
*
* @license http://www.gnu.org/licenses/gpl-3.0.txt GPLv3
*/
final class Cardinality implements \JsonSerializable
{
// Valid cardinality types for data to apply to.

/**
* A Unique Cardinality signifies that the data is unique
* across the scope. Examples of unique data are CandID
* for the candidate scope or VisitLabel for the Session
* scope.
*/
const UNIQUE = 1;

/**
* A Single Cardinality signifies that each data point in
* the scope should have exactly one value. For instance,
* date of birth for a candidate in the candidate scope.
*/
const SINGLE = 2;

/**
* An Optional Cardinality signifies that each data point
* in the scope may have zero or one value. For instance,
* the date of death for a candidate in the candidate scope.
*/
const OPTIONAL = 3;

/**
* A Many Cardinality signifies that each data point will
* have zero or more values associated. For instance,
* the T1 scans acquired at a session.
*/
const MANY = 4;

protected $cardinality;

/**
* Constructs a Scope object. $scope should be a class constant
* to construct the scope for, not an int literal.
*
* @param int $scope The scope
*/
public function __construct(int $card)
{
switch ($card) {
case self::UNIQUE: // fallthrough
case self::SINGLE: // fallthrough
case self::OPTIONAL: // fallthrough
case self::MANY: // fallthrough
$this->cardinality = $card;
break;
default:
throw new \DomainException("Invalid cardinality");
}
}

/**
* Convert the enumeration from a memory-friendly integer to a
* human-readable string when used in a string context.
*
* @return string
*/
public function __toString() : string
{
switch ($this->cardinality) {
case self::UNIQUE: // fallthrough
return "unique";
case self::SINGLE: // fallthrough
return "single";
case self::OPTIONAL: // fallthrough
return "optional";
case self::MANY: // fallthrough
return "many";
default:
return "invalid cardinality";
}
}

/**
* Implement the JsonSerializable interface by
* converting to a string
*
* @return string
*/
public function jsonSerialize() : string
{
return $this->__toString();
}
}
78 changes: 78 additions & 0 deletions src/Data/Dictionary/Category.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
<?php
declare(strict_types=1);
namespace LORIS\Data\Dictionary;

/**
* A \LORIS\Data\Dictionary\Category represents a grouping of
* DictionaryItems.
*
* @license http://www.gnu.org/licenses/gpl-3.0.txt GPLv3
*/
class Category
{
protected $name;
protected $description;
protected $items = null;

/**
* Construct a dictionary Category
*
* @param string $name The machine name of the category
* @param string $desc The human readable description of
* the category
* @param ?DictionaryItem[] $items An optional iterable of items which
* the category contains.
*/
public function __construct(string $name, string $desc, ?iterable $items = null)
{
$this->name = $name;
$this->description = $desc;
$this->items = $items;
}

/**
* Return the name of the Category
*
* @return string
*/
public function getName() : string
{
return $this->name;
}

/**
* Return the human readable description of the Category
*
* @return string
*/
public function getDescription() : string
{
return $this->description;
}

/**
* Return the items which belong to the Category
*
* @return ?DictionaryItem[]
*/
public function getItems() : ?iterable
{
return $this->items;
}

/**
* Returns a new Category identical to this category, but with
* the items populated with $items. This can be used when the items
* were not yet known at the time the constructor was called.
*
* @param DictionaryItem[] $items The items to add to the new Category
*
* @return Category
*/
public function withItems(iterable $items) : Category
{
$c = clone($this);
$c->items = $items;
return $c;
}
}
117 changes: 117 additions & 0 deletions src/Data/Dictionary/DictionaryItem.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
<?php
declare(strict_types=1);
namespace LORIS\Data\Dictionary;

use \LORIS\Data\Scope;
use \LORIS\Data\Type;
use \LORIS\Data\Cardinality;

/**
* A DictionaryItem represents a description of a type of data
* managed by LORIS.
*
* @license http://www.gnu.org/licenses/gpl-3.0.txt GPLv3
*/
class DictionaryItem implements \LORIS\StudyEntities\AccessibleResource
{
protected $name;
protected $description;
protected $scope;
protected $typ;

/**
* Construct a DictionaryItem with the given parameters
*
* @param string $name The field name of the dictionary item
* @param string $desc The dictionary item's description
* @param Scope $scope The scope to which this DictionaryItem
* applies
* @param Type $t The data type of this dictionary item
* @param Cardinality $c The data cardinality
*/
public function __construct(
string $name,
string $desc,
Scope $scope,
Type $t,
Cardinality $c
) {
$this->name = $name;
$this->description = $desc;
$this->scope = $scope;
$this->typ = $t;
$this->cardinality = $c;
}

/**
* Return the field name of this DictionaryItem
*
* @return string
*/
public function getName() : string
{
return $this->name;
}

/**
* Return a human readable description of this DictionaryItem.
*
* @return string
*/
public function getDescription() : string
{
return $this->description;
}

/**
* Return the data scope at which the data for this DictionaryItem
* applies.
*
* @return Scope
*/
public function getScope() : Scope
{
return $this->scope;
}

/**
* Return the data type for the data which this DictionaryItem
* describes.
*
* @return \LORIS\Data\Type
*/
public function getDataType() : \LORIS\Data\Type
{
return $this->typ;
}

/**
* Return the data cardinality of this DictionaryItem. ie. for
* each entity of type Scope how many pieces of data should
* exist for this DictionaryItem.
*
* @return \LORIS\Data\Cardinality
*/
public function getCardinality() : \LORIS\Data\Cardinality
{
return $this->cardinality;
}

/**
* The DictionaryItem instance implements the AccessibleResource
* interface in order to make it possible to restrict items per
* user. However, by default DictionaryItems are accessible by
* all users. In order to restrict access to certain items, a
* module would need to extend this class and override the
* isAccessibleBy method with its prefered business logic.
*
* @param \User $user The user whose access should be
* validated
*
* @return bool
*/
public function isAccessibleBy(\User $user): bool
{
return true;
}
}
67 changes: 67 additions & 0 deletions src/Data/Scope.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
<?php
namespace LORIS\Data;

/**
* A Scope is an enumeration class which represents the scope
* that a piece of data may apply to in LORIS.
*
* The Scope class is final because the list of enumeration types
* can not be dynamically extended without modifying all places
* that must deal with the enumeration options.
*
* @license http://www.gnu.org/licenses/gpl-3.0.txt GPLv3
*/
final class Scope implements \JsonSerializable
{
// Valid scopes for data to apply to.
const CANDIDATE = 1;
const SESSION = 2;

/**
* The value of the current scope instance
*/
protected $scope;

/**
* Constructs a Scope object. $scope should be a class constant
* to construct the scope for, not an int literal.
*
* @param int $scope The scope
*/
public function __construct(int $scope)
{
switch ($scope) {
case self::CANDIDATE: // fallthrough
case self::SESSION:
$this->scope = $scope;
break;
default:
throw new \DomainException("Invalid scope");
}
}

/**
* Convert the enumeration from a memory-friendly integer to a
* human-readable string when used in a string context.
*
* @return string
*/
public function __toString() : string
{
switch ($this->scope) {
case self::CANDIDATE:
return "candidate";
case self::SESSION:
return "session";
default:
// This shouldn't happen since the constructor threw an
// exception for an invalid value.
return "invalid scope";
}
}

public function jsonSerialize()
{
return $this->__toString();
}
}
Loading

0 comments on commit 20bf05b

Please sign in to comment.