Skip to content

Commit

Permalink
Add data types LanguageMapOfStrings and LanguageMapOfLists
Browse files Browse the repository at this point in the history
  • Loading branch information
nichtich committed Apr 26, 2017
1 parent 1206156 commit e99f9b5
Show file tree
Hide file tree
Showing 12 changed files with 376 additions and 25 deletions.
4 changes: 4 additions & 0 deletions CHANGES.md
Expand Up @@ -2,6 +2,10 @@

This changelog tracks features and fixes of jskos PHP library.

## 0.1.3

* Add data types LanguageMapOfStrings and LanguageMapOfLists

## 0.1.2

* Extent Sets and List with map and implode
Expand Down
20 changes: 11 additions & 9 deletions src/Container.php
Expand Up @@ -5,7 +5,7 @@
use InvalidArgumentException;

/**
* Common base class of JSKOS Listings and Sets
* Common base class of JSKOS Listing, Set, and LanguageMap
*/
abstract class Container extends PrettyJsonSerializable implements \Countable, \ArrayAccess, \IteratorAggregate
{
Expand All @@ -25,14 +25,6 @@ public function __construct(array $members = [])
}
}

/**
* Return the number of known values in this container (closed or not).
*/
public function count(): int
{
return count($this->members);
}

/**
* Apply a function to each member of this container.
* @param $callback callable
Expand Down Expand Up @@ -73,6 +65,16 @@ public function setClosed(bool $closed = true)
$this->closed = $closed;
}

# implements Countable

/**
* Return the number of known values in this container (closed or not).
*/
public function count(): int
{
return count($this->members);
}

# implements ArrayAccess:

/**
Expand Down
27 changes: 25 additions & 2 deletions src/DataType.php
Expand Up @@ -77,6 +77,14 @@ protected function setField(string $field, $value, bool $strict=true)
# TODO: check member types
}
}
} elseif ($type == 'LanguageMapOfStrings') {
if (!(is_object($value) and $value instanceof LanguageMapOfStrings)) {
$value = new LanguageMapOfStrings($value);
}
} elseif ($type == 'LanguageMapOfLists') {
if (!(is_object($value) and $value instanceof LanguageMapOfLists)) {
$value = new LanguageMapOfLists($value);
}
} elseif (!DataType::hasType($value, $type)) {
$msg = get_called_class()."->$field must match JSKOS\DataType::is$type";
throw new InvalidArgumentException($msg);
Expand All @@ -90,11 +98,16 @@ public function __set($field, $value)
$this->setField($field, $value);
}

public function __get($field)
public function &__get($field)
{
$type = static::fieldType($field);
if ($type) {
return $this->$field;
if (is_null($this->$field)) {
$null = null;
return $null;
} else {
return $this->$field;
}
} else {
trigger_error(
"Undefined property: ".get_called_class()."::$$field",
Expand Down Expand Up @@ -178,6 +191,16 @@ public static function isLanguageRange($range): bool
preg_match(LANGUAGE_RANGE_PATTERN, $range) === 1;
}

/**
* Check whether a given value looks like a language or language range.
*/
public static function isLanguageOrRange($language): bool
{
return is_string($language) and
(preg_match(LANGUAGE_PATTERN, $language) === 1 or
preg_match(LANGUAGE_RANGE_PATTERN, $language) === 1);
}

/**
* Check whether a given value is a string.
*/
Expand Down
27 changes: 17 additions & 10 deletions src/Item.php
Expand Up @@ -13,7 +13,14 @@ abstract class Item extends Object
'url' => 'URL',
'identifier' => ['Listing'],
'notation' => ['Listing'],
# TODO: labels and descriptions
'prefLabel' => 'LanguageMapOfStrings',
'altLabel' => 'LanguageMapOfLists',
'hiddenLabel' => 'LanguageMapOfLists',
'scopeNote' => 'LanguageMapOfLists',
'definition' => 'LanguageMapOfLists',
'example' => 'LanguageMapOfLists',
'historyNote' => 'LanguageMapOfLists',
'changeNote' => 'LanguageMapOfLists',
'subject' => ['Set','Concept'],
'subjectOf' => ['Set','Concept'],
'depiction' => ['Listing'],
Expand All @@ -37,47 +44,47 @@ abstract class Item extends Object
/**
* Preferred labels.
*/
public $prefLabel;
protected $prefLabel;

/**
* Alternative labels.
*/
public $altLabel;
protected $altLabel;

/**
* Hidden labels.
*/
public $hiddenLabel;
protected $hiddenLabel;

/**
* Scope notes.
*/
public $scopeNote;
protected $scopeNote;

/**
* Definitions.
*/
public $definition;
protected $definition;

/**
* Examples.
*/
public $example;
protected $example;

/**
* History notes.
*/
public $historyNote;
protected $historyNote;

/**
* Editorial notes.
*/
public $editorialNote;
protected $editorialNote;

/**
* Change notes.
*/
public $changeNote;
protected $changeNote;

/**
* Topics of the item.
Expand Down
85 changes: 85 additions & 0 deletions src/LanguageMap.php
@@ -0,0 +1,85 @@
<?php declare(strict_types=1);

namespace JSKOS;

use InvalidArgumentException;

/**
* Language map of strings or lists.
*/
abstract class LanguageMap extends Container
{

/**
* Create a new Language Map
*
* @param String|Array|Object JSON data to copy
*/
public function __construct($data=null, bool $strict=false)
{
// FIXME: this is a verbose copy of DataType::__construct
if (is_string($data)) {
$data = json_decode($data);
}
if (is_array($data) or is_object($data)) {
foreach ($data as $key => $value) {
$this->setField($key, $value, $strict);
}
} elseif ($data !== null) {
throw new InvalidArgumentException(
get_called_class() .
' constructor expects array, object, or JSON string'
);
}
}

protected function setField($key, $value, $strict)
{
try {
$this->offsetSet($key, $value);
} catch (InvalidArgumentException $e) {
if ($strict) {
throw $e;
}
}
}

/**
* Language maps are always closed world, so this does nothing.
* @param Boolean $closed
*/
public function setClosed(bool $closed = true)
{
}


/**
* Set an value at the given language or language range.
* @param mixed $lang
* @param mixed $value
*/
public function offsetSet($lang, $value)
{
if (DataType::isLanguageOrRange($lang)) {
if (is_null($value)) {
unset($this->members[$lang]);
} else {
$this->members[$lang] = static::checkMember($value);
}
} else {
throw new InvalidArgumentException(
'JSKOS\LanguageMap may only use language tags or ranges as index'
);
}
}


/**
* Unset a value with given language or language range.
* @param mixed $lang
*/
public function offsetUnset($lang)
{
unset($this->members[$lang]);
}
}
40 changes: 40 additions & 0 deletions src/LanguageMapOfLists.php
@@ -0,0 +1,40 @@
<?php declare(strict_types=1);

namespace JSKOS;

use InvalidArgumentException;
use TypeError;

/**
* Language map of strings.
*/
class LanguageMapOfLists extends LanguageMap
{
protected static function checkMember($value)
{
if (is_object($value) and $value instanceof Listing) {
return $value;
} else {
try {
return new Listing($value);
} catch (TypeError $e) {
throw new InvalidArgumentException(
'JSKOS\LanguageMapOfLists may only contain JSKOS\Listing'
);
}
}
}


/**
* Return a data structure to serialize this container as JSON.
*/
public function jsonSerializeRoot($context=self::DEFAULT_CONTEXT)
{
$map = new \stdClass();
foreach ($this->members as $lang => $list) {
$map->$lang = $list->jsonSerializeRoot(null);
}
return $map;
}
}
31 changes: 31 additions & 0 deletions src/LanguageMapOfStrings.php
@@ -0,0 +1,31 @@
<?php declare(strict_types=1);

namespace JSKOS;

use InvalidArgumentException;

/**
* Language map of strings.
*/
class LanguageMapOfStrings extends LanguageMap
{
protected static function checkMember($value)
{
if (is_string($value)) {
return $value;
} else {
throw new InvalidArgumentException(
'JSKOS\LanguageMapOfStrings may only contain strings'
);
}
}


/**
* Return a data structure to serialize this container as JSON.
*/
public function jsonSerializeRoot($context=self::DEFAULT_CONTEXT)
{
return (object)$this->members;
}
}
2 changes: 1 addition & 1 deletion tests/ConceptTest.php
Expand Up @@ -26,7 +26,7 @@ public function testCreate()
public function testJson()
{
$concept = new Concept(['uri'=>'x:1']);
$concept->prefLabel['en'] = 'test';
$concept->prefLabel = ['en' => 'test'];

$concept->narrower = [];
$concept->narrower[] = new Concept(['uri'=>'x:2']);
Expand Down

0 comments on commit e99f9b5

Please sign in to comment.