1
0

downgrade to kirby v3

This commit is contained in:
Philip Wagner
2024-09-01 10:47:15 +02:00
parent a4b2aece7b
commit af86acb7a1
1085 changed files with 54743 additions and 65042 deletions

3
vendor/ml/iri/ML/IRI/.gitignore vendored Normal file
View File

@@ -0,0 +1,3 @@
/Test/report

7
vendor/ml/iri/ML/IRI/.travis.yml vendored Normal file
View File

@@ -0,0 +1,7 @@
language: php
php:
- 5.3
- 5.4
- 5.5
- hhvm

601
vendor/ml/iri/ML/IRI/IRI.php vendored Normal file
View File

@@ -0,0 +1,601 @@
<?php
/*
* (c) Markus Lanthaler <mail@markus-lanthaler.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace ML\IRI;
/**
* IRI represents an IRI as per RFC3987.
*
* @author Markus Lanthaler <mail@markus-lanthaler.com>
*
* @link http://tools.ietf.org/html/rfc3987 RFC3987
*/
class IRI
{
/**
* The scheme
*
* @var string|null
*/
private $scheme = null;
/**
* The user information
*
* @var string|null
*/
private $userinfo = null;
/**
* The host
*
* @var string|null
*/
private $host = null;
/**
* The port
*
* @var string|null
*/
private $port = null;
/**
* The path
*
* @var string
*/
private $path = '';
/**
* The query component
*
* @var string|null
*/
private $query = null;
/**
* The fragment identifier
*
* @var string|null
*/
private $fragment = null;
/**
* Constructor
*
* @param null|string|IRI $iri The IRI.
*
* @throws \InvalidArgumentException If an invalid IRI is passed.
*
* @api
*/
public function __construct($iri = null)
{
if (null === $iri) {
return;
} elseif (is_string($iri)) {
$this->parse($iri);
} elseif ($iri instanceof IRI) {
$this->scheme = $iri->scheme;
$this->userinfo = $iri->userinfo;
$this->host = $iri->host;
$this->port = $iri->port;
$this->path = $iri->path;
$this->query = $iri->query;
$this->fragment = $iri->fragment;
} else {
throw new \InvalidArgumentException(
'Expecting a string or an IRI, got ' .
(is_object($iri) ? get_class($iri) : gettype($iri))
);
}
}
/**
* Get the scheme
*
* @return string|null Returns the scheme or null if not set.
*/
public function getScheme()
{
return $this->scheme;
}
/**
* Get the authority
*
* @return string|null Returns the authority or null if not set.
*/
public function getAuthority()
{
$authority = null;
if (null !== $this->host) {
if (null !== $this->userinfo) {
$authority .= $this->userinfo . '@';
}
$authority .= $this->host;
if (null !== $this->port) {
$authority .= ':' . $this->port;
}
}
return $authority;
}
/**
* Get the user information
*
* @return string|null Returns the user information or null if not set.
*/
public function getUserInfo()
{
return $this->userinfo;
}
/**
* Get the host
*
* @return string|null Returns the host or null if not set.
*/
public function getHost()
{
return $this->host;
}
/**
* Get the port
*
* @return string|null Returns the port or null if not set.
*/
public function getPort()
{
return $this->port;
}
/**
* Get the path
*
* @return string Returns the path which might be empty.
*/
public function getPath()
{
return $this->path;
}
/**
* Get the query component
*
* @return string|null Returns the query component or null if not set.
*/
public function getQuery()
{
return $this->query;
}
/**
* Get the fragment identifier
*
* @return string|null Returns the fragment identifier or null if not set.
*/
public function getFragment()
{
return $this->fragment;
}
/**
* Find out whether the IRI is absolute
*
* @return bool Returns true if the IRI is absolute, false otherwise.
*
* @api
*/
public function isAbsolute()
{
return (null !== $this->scheme);
}
/**
* Get as absolute IRI, i.e., without fragment identifier
*
* @return IRI The absolute IRI, i.e., without fragment identifier
*
* @throws \UnexpectedValueException If the IRI is a relative IRI.
*
* @link http://tools.ietf.org/html/rfc3987#section-2.2 RFC3987 absolute-IRI
*
* @api
*/
public function getAbsoluteIri()
{
if (false === $this->isAbsolute()) {
throw new \UnexpectedValueException('Cannot get the absolute IRI of a relative IRI.');
}
$absolute = clone $this;
$absolute->fragment = null;
return $absolute;
}
/**
* Check whether the passed IRI is equal
*
* @param IRI|string $iri IRI to compare to this instance.
*
* @return bool Returns true if the two IRIs are equal, false otherwise.
*
* @api
*/
public function equals($iri)
{
// Make sure both instances are strings
return ($this->__toString() === (string)$iri);
}
/**
* Resolve a (relative) IRI reference against this IRI
*
* @param IRI|string $reference The (relative) IRI reference that should
* be resolved against this IRI.
*
* @return IRI The resolved IRI.
*
* @throws \InvalidArgumentException If an invalid IRI is passed.
*
* @link http://tools.ietf.org/html/rfc3986#section-5.2
*
* @api
*/
public function resolve($reference)
{
$reference = new IRI($reference);
$scheme = null;
$authority = null;
$path = '';
$query = null;
$fragment = null;
// The Transform References algorithm as specified by RFC3986
// see: http://tools.ietf.org/html/rfc3986#section-5.2.2
if ($reference->scheme) {
$scheme = $reference->scheme;
$authority = $reference->getAuthority();
$path = self::removeDotSegments($reference->path);
$query = $reference->query;
} else {
if (null !== $reference->getAuthority()) {
$authority = $reference->getAuthority();
$path = self::removeDotSegments($reference->path);
$query = $reference->query;
} else {
if (0 === strlen($reference->path)) {
$path = $this->path;
if (null !== $reference->query) {
$query = $reference->query;
} else {
$query = $this->query;
}
} else {
if ('/' === $reference->path[0]) {
$path = self::removeDotSegments($reference->path);
} else {
// T.path = merge(Base.path, R.path);
if ((null !== $this->getAuthority()) && ('' === $this->path)) {
$path = '/' . $reference->path;
} else {
if (false !== ($end = strrpos($this->path, '/'))) {
$path = substr($this->path, 0, $end + 1);
}
$path .= $reference->path;
}
$path = self::removeDotSegments($path);
}
$query = $reference->query;
}
$authority = $this->getAuthority();
}
$scheme = $this->scheme;
}
$fragment = $reference->fragment;
// The Component Recomposition algorithm as specified by RFC3986
// see: http://tools.ietf.org/html/rfc3986#section-5.3
$result = '';
if ($scheme) {
$result = $scheme . ':';
}
if (null !== $authority) {
$result .= '//' . $authority;
}
$result .= $path;
if (null !== $query) {
$result .= '?' . $query;
}
if (null !== $fragment) {
$result .= '#' . $fragment;
}
return new IRI($result);
}
/**
* Transform this IRI to a IRI reference relative to the passed base IRI
*
* @param IRI|string $base The (relative) IRI reference that should be
* be used as base IRI.
* @param bool Defines whether schema-relative IRIs such
* as `//example.com` should be created (`true`)
* or not (`false`).
*
* @return IRI The IRI reference relative to the passed base IRI.
*
* @throws \InvalidArgumentException If an invalid IRI is passed.
*
* @api
*/
public function relativeTo($base, $schemaRelative = false)
{
if (false === ($base instanceof IRI)) {
$base = new IRI($base);
}
$relative = clone $this;
// Compare scheme
if ($relative->scheme !== $base->scheme) {
return $relative;
}
// Compare authority
if ($relative->getAuthority() !== $base->getAuthority()) {
if (true === $schemaRelative) {
$relative->scheme = null;
}
return $relative;
}
$relative->scheme = null;
$relative->host = null;
$relative->userinfo = null;
$relative->port = null;
// Compare path
$baseSegments = explode('/', $base->path);
$relativeSegments = explode('/', $relative->path);
$len = min(count($baseSegments), count($relativeSegments)) - 1; // do not move beyond last segment
$pos = 0;
while (($baseSegments[$pos] === $relativeSegments[$pos]) && ($pos < $len)) {
$pos++;
}
$relative->path = '';
$numBaseSegments = count($baseSegments) - $pos - 1;
if ($numBaseSegments > 0) {
$relative->path .= str_repeat('../', $numBaseSegments);
}
if (($baseSegments[$pos] !== $relativeSegments[$pos]) ||
((null === $relative->query) && (null === $relative->fragment))) {
// if the two paths differ or if there's neither a query component nor a fragment,
// we need to consider this IRI's path
if (($relative->path === '') && (false !== strpos($relativeSegments[$pos], ':'))) {
// if the first path segment contains a colon, we need to
// prepend a ./ to distinguish it from an absolute IRI
$relative->path .= './';
}
$relative->path .= implode('/', array_slice($relativeSegments, $pos));
// .. and ensure that the resulting path isn't empty
if (($relative->path === '')) {
$relative->path .= './';
}
}
if ($relative->query !== $base->query) {
return $relative;
}
if (null !== $relative->fragment) {
$relative->query = null;
}
return $relative;
}
/**
* Convert an IRI to a relative IRI reference using this IRI as base
*
* This method provides a more convenient interface than the
* {@link IRI::relativeTo()} method if the base IRI stays the same while
* the IRIs to convert to relative IRI references change.
*
* @param string|IRI $iri The IRI to convert to a relative reference
* @param bool Defines whether schema-relative IRIs such
* as `//example.com` should be created (`true`)
* or not (`false`).
*
* @throws \InvalidArgumentException If an invalid IRI is passed.
*
* @see \ML\IRI\IRI::relativeTo()
*
* @return IRI The relative IRI reference
*/
public function baseFor($iri, $schemaRelative = false)
{
if (false === ($iri instanceof IRI)) {
$iri = new IRI($iri);
}
return $iri->relativeTo($this, $schemaRelative);
}
/**
* Get a string representation of this IRI object
*
* @return string A string representation of this IRI instance.
*
* @api
*/
public function __toString()
{
$result = '';
if ($this->scheme) {
$result .= $this->scheme . ':';
}
if (null !== ($authority = $this->getAuthority())) {
$result .= '//' . $authority;
}
$result .= $this->path;
if (null !== $this->query) {
$result .= '?' . $this->query;
}
if (null !== $this->fragment) {
$result .= '#' . $this->fragment;
}
return $result;
}
/**
* Parse an IRI into it's components
*
* This is done according to
* {@link http://tools.ietf.org/html/rfc3986#section-3.1 RFC3986}.
*
* @param string $iri The IRI to parse.
*/
protected function parse($iri)
{
// Parse IRI by using the regular expression as specified by
// http://tools.ietf.org/html/rfc3986#appendix-B
$regex = '|^((?P<scheme>[^:/?#]+):)?' .
'((?P<doubleslash>//)(?P<authority>[^/?#]*))?(?P<path>[^?#]*)' .
'((?P<querydef>\?)(?P<query>[^#]*))?(#(?P<fragment>.*))?|';
preg_match($regex, $iri, $match);
// Extract scheme
if (false === empty($match['scheme'])) {
$this->scheme = $match['scheme'];
}
// Parse authority (http://tools.ietf.org/html/rfc3986#section-3.2)
if ('//' === $match['doubleslash']) {
if (0 === strlen($match['authority'])) {
$this->host = '';
} else {
$authority = $match['authority'];
// Split authority into userinfo and host
// (use last @ to ignore unescaped @ symbols)
if (false !== ($pos = strrpos($authority, '@'))) {
$this->userinfo = substr($authority, 0, $pos);
$authority = substr($authority, $pos + 1);
}
// Split authority into host and port
$hostEnd = 0;
if (('[' === $authority[0]) && (false !== ($pos = strpos($authority, ']')))) {
$hostEnd = $pos;
}
if ((false !== ($pos = strrpos($authority, ':'))) && ($pos > $hostEnd)) {
$this->host = substr($authority, 0, $pos);
$this->port = substr($authority, $pos + 1);
} else {
$this->host = $authority;
}
}
}
// Extract path (http://tools.ietf.org/html/rfc3986#section-3.3)
// The path is always present but might be empty
$this->path = $match['path'];
// Extract query (http://tools.ietf.org/html/rfc3986#section-3.4)
if (false === empty($match['querydef'])) {
$this->query = $match['query'];
}
// Extract fragment (http://tools.ietf.org/html/rfc3986#section-3.5)
if (isset($match['fragment'])) {
$this->fragment = $match['fragment'];
}
}
/**
* Remove dot-segments
*
* This method removes the special "." and ".." complete path segments
* from an IRI.
*
* @param string $input The IRI from which dot segments should be removed.
*
* @return string The IRI with all dot-segments removed.
*
* @link http://tools.ietf.org/html/rfc3986#section-5.2.4
*/
private static function removeDotSegments($input)
{
$output = '';
while (strlen($input) > 0) {
if (('../' === substr($input, 0, 3)) || ('./' === substr($input, 0, 2))) {
$input = substr($input, strpos($input, '/'));
} elseif ('/./' === substr($input, 0, 3)) {
$input = substr($input, 2);
} elseif ('/.' === $input) {
$input = '/';
} elseif (('/../' === substr($input, 0, 4)) || ('/..' === $input)) {
if ($input == '/..') {
$input = '/';
} else {
$input = substr($input, 3);
}
if (false !== ($end = strrpos($output, '/'))) {
$output = substr($output, 0, $end);
} else {
$output = '';
}
} elseif (('..' === $input) || ('.' === $input)) {
$input = '';
} else {
if (false === ($end = strpos($input, '/', 1))) {
$output .= $input;
$input = '';
} else {
$output .= substr($input, 0, $end);
$input = substr($input, $end);
}
}
}
return $output;
}
}

19
vendor/ml/iri/ML/IRI/LICENSE vendored Normal file
View File

@@ -0,0 +1,19 @@
Copyright (c) 2012-2013 Markus Lanthaler
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.

47
vendor/ml/iri/ML/IRI/README.md vendored Normal file
View File

@@ -0,0 +1,47 @@
IRI
==============
This is a simple PHP class to ease IRI handling. Currently it just supports
parsing of IRIs and relative IRI resolution. In the future I will extend it
to support validation and normalization and perhaps also support for IRI
templates.
With more than 700 tests, this class is extensively unit tested:
[![Build Status](https://secure.travis-ci.org/lanthaler/IRI.png?branch=master)](http://travis-ci.org/lanthaler/IRI)
Installation
------------
The easiest way to use IRI is to integrate it as a dependency in your project's
[composer.json](http://getcomposer.org/doc/00-intro.md) file:
```json
{
"require": {
"ml/iri": "1.*"
}
}
```
Installing is then a matter of running composer
php composer.phar install
... and including Composer's autoloader to your project
```php
require('vendor/autoload.php');
```
Of course you can also just download an [archive](https://github.com/lanthaler/IRI/downloads)
from Github.
Credits
------------
Most test cases come either directly from the [URI specification](http://tools.ietf.org/html/rfc3986),
from [Graham Klyne's](http://www.ninebynine.org/Software/HaskellUtils/Network/URITestDescriptions.html),
or [Tim Berners-Lee's](http://dig.csail.mit.edu/2005/ajar/ajaw/test/uri-test-doc.html) test suite.

1078
vendor/ml/iri/ML/IRI/Test/IriTest.php vendored Normal file

File diff suppressed because it is too large Load Diff

12
vendor/ml/iri/ML/IRI/Test/bootstrap.php vendored Normal file
View File

@@ -0,0 +1,12 @@
<?php
// @codingStandardsIgnoreFile
spl_autoload_register(function($class)
{
if (0 === strpos($class, 'ML\\IRI\\')) {
$path = implode('/', array_slice(explode('\\', $class), 2)).'.php';
require_once __DIR__.'/../'.$path;
return true;
}
});

24
vendor/ml/iri/ML/IRI/composer.json vendored Normal file
View File

@@ -0,0 +1,24 @@
{
"name": "ml/iri",
"type": "library",
"description": "IRI handling for PHP",
"keywords": [ "IRI", "URL", "URI", "URN" ],
"homepage": "http://www.markus-lanthaler.com",
"license": "MIT",
"authors": [
{
"name": "Markus Lanthaler",
"email": "mail@markus-lanthaler.com",
"homepage": "http://www.markus-lanthaler.com",
"role": "Developer"
}
],
"require": {
"php": ">=5.3.0",
"lib-pcre": ">=4.0"
},
"autoload": {
"psr-0": { "ML\\IRI": "" }
},
"target-dir": "ML/IRI"
}

32
vendor/ml/iri/ML/IRI/phpunit.xml.dist vendored Normal file
View File

@@ -0,0 +1,32 @@
<?xml version="1.0" encoding="UTF-8"?>
<phpunit backupGlobals="false"
backupStaticAttributes="false"
colors="true"
convertErrorsToExceptions="true"
convertNoticesToExceptions="true"
convertWarningsToExceptions="true"
processIsolation="false"
stopOnFailure="false"
strict="true"
bootstrap="./Test/bootstrap.php">
<testsuites>
<testsuite name="IRI Test Suite">
<directory suffix="Test.php">./Test/</directory>
</testsuite>
</testsuites>
<filter>
<whitelist processUncoveredFilesFromWhitelist="true">
<directory>./</directory>
<exclude>
<directory>./Test</directory>
</exclude>
</whitelist>
</filter>
<logging>
<log type="coverage-text" target="php://stdout" showUncoveredFiles="true" />
</logging>
</phpunit>

View File

@@ -0,0 +1,16 @@
# See here for image contents: https://github.com/microsoft/vscode-dev-containers/tree/v0.245.2/containers/php/.devcontainer/base.Dockerfile
# [Choice] PHP version (use -bullseye variants on local arm64/Apple Silicon): 8, 8.1, 8.0, 7, 7.4, 7.3, 8-bullseye, 8.1-bullseye, 8.0-bullseye, 7-bullseye, 7.4-bullseye, 7.3-bullseye, 8-buster, 8.1-buster, 8.0-buster, 7-buster, 7.4-buster
ARG VARIANT="8.1-apache-bullseye"
FROM mcr.microsoft.com/vscode/devcontainers/php:0-${VARIANT}
# [Choice] Node.js version: none, lts/*, 16, 14, 12, 10
ARG NODE_VERSION="none"
RUN if [ "${NODE_VERSION}" != "none" ]; then su vscode -c "umask 0002 && . /usr/local/share/nvm/nvm.sh && nvm install ${NODE_VERSION} 2>&1"; fi
# Enables Xdebug code coverage analysis to generate code coverage reports, mainly in combination with PHPUnit.
RUN echo "xdebug.mode = coverage" >> /usr/local/etc/php/conf.d/xdebug.ini \
&& echo "xdebug.start_with_request = trigger" >> /usr/local/etc/php/conf.d/xdebug.ini
# [Optional] Uncomment this line to install global node packages.
# RUN su vscode -c "source /usr/local/share/nvm/nvm.sh && npm install -g <your-package-here>" 2>&1

View File

@@ -0,0 +1,46 @@
// For format details, see https://aka.ms/devcontainer.json. For config options, see the README at:
// https://github.com/microsoft/vscode-dev-containers/tree/v0.245.2/containers/php
{
"name": "PHP",
"build": {
"dockerfile": "Dockerfile",
"args": {
// Update VARIANT to pick a PHP version: 8, 8.1, 8.0, 7, 7.4
// Append -bullseye or -buster to pin to an OS version.
// Use -bullseye variants on local on arm64/Apple Silicon.
"VARIANT": "7.4",
"NODE_VERSION": "lts/*"
}
},
// Configure tool-specific properties.
"customizations": {
// Configure properties specific to VS Code.
"vscode": {
// Set *default* container specific settings.json values on container create.
"settings": {
"php.validate.executablePath": "/usr/local/bin/php",
"debug.console.collapseIdenticalLines": false
},
// Add the IDs of extensions you want installed when the container is created.
"extensions": [
"xdebug.php-debug",
"bmewburn.vscode-intelephense-client",
"mrmlnc.vscode-apache"
]
}
},
// Use 'forwardPorts' to make a list of ports inside the container available locally.
"forwardPorts": [8080],
// Use 'postCreateCommand' to run commands after the container is created.
// "postCreateCommand": "sudo chmod a+x \"$(pwd)\" && sudo rm -rf /var/www/html && sudo ln -s \"$(pwd)\" /var/www/html"
// Comment out to connect as root instead. More info: https://aka.ms/vscode-remote/containers/non-root.
"remoteUser": "vscode",
"features": {
"git": "os-provided"
}
}

View File

@@ -0,0 +1,43 @@
name: Continuous integration
on:
push:
branches: [ master ]
pull_request:
branches: [ master ]
jobs:
ci:
runs-on: ubuntu-latest
env:
extensions: intl, mbstring, xdebug
strategy:
matrix:
php-version:
- "5.3"
- "5.4"
- "5.5"
- "5.6"
- "7.0"
- "7.1"
- "7.2"
- "7.3"
- "7.4"
steps:
- name: "Install PHP"
uses: "shivammathur/setup-php@v2"
with:
php-version: "${{ matrix.php-version }}"
extensions: "${{ env.extensions }}"
ini-values: "memory_limit=-1, error_reporting=E_ALL, display_errors=On"
coverage: xdebug
tools: composer
- name: Checkout code
uses: actions/checkout@v3
- name: Download dependencies
run: composer update --no-interaction --no-progress
- name: Run tests
run: vendor/bin/phpunit

4
vendor/ml/json-ld/.gitignore vendored Normal file
View File

@@ -0,0 +1,4 @@
/vendor
/composer.lock
/phpunit.xml
/earl-report.jsonld

29
vendor/ml/json-ld/.vscode/launch.json vendored Normal file
View File

@@ -0,0 +1,29 @@
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "Listen for Xdebug",
"type": "php",
"request": "launch",
"port": 9000
},
{
"name": "Run tests",
"type": "php",
"request": "launch",
"program": "${workspaceFolder}/vendor/bin/phpunit",
"cwd": "${workspaceFolder}",
"port": 9000,
"runtimeArgs": [
"-dxdebug.start_with_request=yes"
],
"env": {
"XDEBUG_MODE": "debug,develop,coverage",
"XDEBUG_CONFIG": "client_port=${port}"
}
}
]
}

View File

@@ -0,0 +1,28 @@
<?php
/*
* (c) Markus Lanthaler <mail@markus-lanthaler.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace ML\JsonLD;
/**
* DefaultDocumentFactory creates new Documents
*
* @see Document
*
* @author Markus Lanthaler <mail@markus-lanthaler.com>
*/
class DefaultDocumentFactory implements DocumentFactoryInterface
{
/**
* {@inheritdoc}
*/
public function createDocument($iri = null)
{
return new Document($iri);
}
}

206
vendor/ml/json-ld/Document.php vendored Normal file
View File

@@ -0,0 +1,206 @@
<?php
/*
* (c) Markus Lanthaler <mail@markus-lanthaler.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace ML\JsonLD;
use stdClass as JsonObject;
use ML\IRI\IRI;
/**
* A Document represents a JSON-LD document.
*
* Named graphs are not supported yet.
*
* @author Markus Lanthaler <mail@markus-lanthaler.com>
*/
class Document implements DocumentInterface, JsonLdSerializable
{
/**
* @var IRI The document's IRI
*/
protected $iri = null;
/**
* @var GraphInterface The default graph
*/
protected $defaultGraph = null;
/**
* @var array An associative array holding all named graphs in the document
*/
protected $namedGraphs = array();
/**
* Parses a JSON-LD document and returns it as a Document
*
* The document can be supplied directly as a string or by passing a
* file path or an IRI.
*
* Usage:
* <code>
* $document = Document::load('document.jsonld');
* </code>
*
* <strong>Please note that currently all data is merged into the
* default graph, named graphs are not supported yet!</strong>
*
* It is possible to configure the processing by setting the options
* parameter accordingly. Available options are:
*
* - <em>base</em> The base IRI of the input document.
*
* @param string|array|JsonObject $document The JSON-LD document to process.
* @param null|array|JsonObject $options Options to configure the processing.
*
* @return Document The parsed JSON-LD document.
*
* @throws ParseException If the JSON-LD input document is invalid.
*/
public static function load($document, $options = null)
{
return JsonLD::getDocument($document, $options);
}
/**
* Constructor
*
* @param null|string|IRI $iri The document's IRI
*/
public function __construct($iri = null)
{
$this->iri = new IRI($iri);
$this->defaultGraph = new Graph($this);
}
/**
* {@inheritdoc}
*/
public function setIri($iri)
{
$this->iri = new IRI($iri);
return $this;
}
/**
* {@inheritdoc}
*/
public function getIri($asObject = false)
{
return ($asObject) ? $this->iri : (string) $this->iri;
}
/**
* {@inheritdoc}
*/
public function createGraph($name)
{
$name = (string) $this->iri->resolve($name);
if (isset($this->namedGraphs[$name])) {
return $this->namedGraphs[$name];
}
return $this->namedGraphs[$name] = new Graph($this, $name);
}
/**
* {@inheritdoc}
*/
public function getGraph($name = null)
{
if (null === $name) {
return $this->defaultGraph;
}
$name = (string) $this->iri->resolve($name);
return isset($this->namedGraphs[$name])
? $this->namedGraphs[$name]
: null;
}
/**
* {@inheritdoc}
*/
public function getGraphNames()
{
return array_keys($this->namedGraphs);
}
/**
* {@inheritdoc}
*/
public function containsGraph($name)
{
$name = (string) $this->iri->resolve($name);
return isset($this->namedGraphs[$name]);
}
/**
* {@inheritdoc}
*/
public function removeGraph($graph = null)
{
// The default graph can't be "removed", it can just be reset
if (null === $graph) {
$this->defaultGraph = new Graph($this);
return $this;
}
if ($graph instanceof GraphInterface) {
foreach ($this->namedGraphs as $n => $g) {
if ($g === $graph) {
$name = $n;
break;
}
}
} else {
$name = (string) $this->iri->resolve($graph);
}
if (isset($this->namedGraphs[$name])) {
if ($this->namedGraphs[$name]->getDocument() === $this) {
$this->namedGraphs[$name]->removeFromDocument();
}
unset($this->namedGraphs[$name]);
}
return $this;
}
/**
* {@inheritdoc}
*/
public function toJsonLd($useNativeTypes = true)
{
$defGraph = $this->defaultGraph->toJsonLd($useNativeTypes);
if (0 === count($this->namedGraphs)) {
return $defGraph;
}
foreach ($this->namedGraphs as $graphName => $graph) {
$namedGraph = new JsonObject();
$namedGraph->{'@id'} = $graphName;
$namedGraph->{'@graph'} = $graph->toJsonLd($useNativeTypes);
$defGraph[] = $namedGraph;
}
$document = new JsonObject();
$document->{'@graph'} = $defGraph;
return array($document);
}
}

View File

@@ -0,0 +1,29 @@
<?php
/*
* (c) Markus Lanthaler <mail@markus-lanthaler.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace ML\JsonLD;
/**
* Interface for factories to create DocumentInterface objects
*
* @see DocumentInterface
*
* @author Markus Lanthaler <mail@markus-lanthaler.com>
*/
interface DocumentFactoryInterface
{
/**
* Creates a new document
*
* @param null|string $iri The document's IRI.
*
* @return DocumentInterface The document.
*/
public function createDocument($iri = null);
}

89
vendor/ml/json-ld/DocumentInterface.php vendored Normal file
View File

@@ -0,0 +1,89 @@
<?php
/*
* (c) Markus Lanthaler <mail@markus-lanthaler.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace ML\JsonLD;
use ML\IRI\IRI;
/**
* JSON-LD document interface
*
* @author Markus Lanthaler <mail@markus-lanthaler.com>
*/
interface DocumentInterface
{
/**
* Set the document's IRI
*
* @param string|IRI The IRI.
*
* @return self
*/
public function setIri($iri);
/**
* Get the document's IRI
*
* @param boolean $asObject If set to true, the return value will be an
* {@link IRI} object; otherwise a string.
*
* @return string|IRI The document's IRI (might be empty).
*/
public function getIri($asObject = false);
/**
* Creates a new graph which is linked to this document
*
* If there exists already a graph with the passed name in the document,
* that graph will be returned instead of creating a new one.
*
* @param string|IRI $name The graph's name.
*
* @return GraphInterface The newly created graph.
*/
public function createGraph($name);
/**
* Get a graph by name
*
* @param null|string $name The name of the graph to retrieve. If null
* is passed, the default will be returned.
*
* @return GraphInterface|null Returns the graph if found; null otherwise.
*/
public function getGraph($name = null);
/**
* Get graph names
*
* @return string[] Returns the names of all graphs in the document.
*/
public function getGraphNames();
/**
* Check whether the document contains a graph with the specified name
*
* @param string $name The graph name.
*
* @return bool Returns true if the document contains a graph with the
* specified name; false otherwise.
*/
public function containsGraph($name);
/**
* Removes a graph from the document
*
* @param null|string|GraphInterface $graph The graph (or its name) to
* remove. If null is passed,
* the default will be reset.
*
* @return self
*/
public function removeGraph($graph = null);
}

View File

@@ -0,0 +1,31 @@
<?php
/*
* (c) Markus Lanthaler <mail@markus-lanthaler.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace ML\JsonLD;
use ML\JsonLD\Exception\JsonLdException;
/**
* Interface for (remote) document loaders
*
* @author Markus Lanthaler <mail@markus-lanthaler.com>
*/
interface DocumentLoaderInterface
{
/**
* Load a (remote) document or context
*
* @param string $url The URL or path of the document to load.
*
* @return RemoteDocument The loaded document.
*
* @throws JsonLdException
*/
public function loadDocument($url);
}

View File

@@ -0,0 +1,61 @@
<?php
/*
* (c) Markus Lanthaler <mail@markus-lanthaler.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace ML\JsonLD\Exception;
use ML\JsonLD\Quad;
/**
* Exception that is thrown when an invalid quad is detected.
*
* @author Markus Lanthaler <mail@markus-lanthaler.com>
*/
class InvalidQuadException extends \RuntimeException
{
/**
* The quad that triggered this exception
*
* @var Quad
*/
private $quad;
/**
* Constructor.
*
* @param string $message The error message
* @param Quad $quad The quad
* @param null|\Exception $previous The previous exception
*/
public function __construct($message, $quad, \Exception $previous = null)
{
$this->quad = $quad;
parent::__construct($this->message, 0, $previous);
}
/**
* Gets the quad
*
* @return Quad The quad.
*/
public function getQuad()
{
return $this->quad;
}
/**
* Sets the quad
*
* @param Quad $quad The quad.
*/
public function setQuad($quad)
{
$this->quad = $quad;
}
}

View File

@@ -0,0 +1,307 @@
<?php
/*
* (c) Markus Lanthaler <mail@markus-lanthaler.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace ML\JsonLD\Exception;
use ML\JsonLD\JsonLD;
/**
* Exception class thrown when an error occurs during parsing.
*
* @author Markus Lanthaler <mail@markus-lanthaler.com>
*/
class JsonLdException extends \RuntimeException
{
/**
* An unspecified error code (none was standardized yet)
*/
const UNSPECIFIED = 'unknown';
/**
* The document could not be loaded or parsed as JSON.
*/
const LOADING_DOCUMENT_FAILED = "loading document failed";
/**
* A list of lists was detected. List of lists are not supported in
* this version of JSON-LD due to the algorithmic complexity.
*/
const LIST_OF_LISTS = "list of lists";
/**
* An @index member was encountered whose value was not a string.
*/
const INVALID_INDEX_VALUE = "invalid @index value";
/**
* Multiple conflicting indexes have been found for the same node.
*/
const CONFLICTING_INDEXES = "conflicting indexes";
/**
* An @id member was encountered whose value was not a string.
*/
const INVALID_ID_VALUE = "invalid @id value";
/**
* In invalid local context was detected.
*/
const INVALID_LOCAL_CONTEXT = "invalid local context";
/**
* Multiple HTTP Link Headers [RFC5988] using th
* http://www.w3.org/ns/json-ld#context link relation have been detected.
*/
const MULTIPLE_CONTEXT_LINK_HEADERS = "multiple context link headers";
/**
* There was a problem encountered loading a remote context.
*/
const LOADING_REMOTE_CONTEXT_FAILED = "loading remote context failed";
/**
* No valid context document has been found for a referenced,
* remote context.
*/
const INVALID_REMOTE_CONTEXT = "invalid remote context";
/**
* A cycle in remote context inclusions has been detected.
*/
const RECURSIVE_CONTEXT_INCLUSION = "recursive context inclusion";
/**
* An invalid base IRI has been detected, i.e., it is neither an
* absolute IRI nor null.
*/
const INVALID_BASE_IRI = "invalid base IRI";
/**
* An invalid vocabulary mapping has been detected, i.e., it is
* neither an absolute IRI nor null.
*/
const INVALID_VOCAB_MAPPING = "invalid vocab mapping";
/**
* The value of the default language is not a string or null and
* thus invalid.
*/
const INVALID_DEFAULT_LANGUAGE = "invalid default language";
/**
* A keyword redefinition has been detected.
*/
const KEYWORD_REDEFINITION = "keyword redefinition";
/**
* An invalid term definition has been detected.
*/
const INVALID_TERM_DEFINITION = "invalid term definition";
/**
* An invalid reverse property definition has been detected.
*/
const INVALID_REVERSE_PROPERTY = "invalid reverse property";
/**
* IRI mapping A local context contains a term that has an invalid
* or missing IRI mapping.
*/
const INVALID_IRI_MAPPING = "invalid IRI mapping";
/**
* IRI mapping A cycle in IRI mappings has been detected.
*/
const CYCLIC_IRI_MAPPING = "cyclic IRI mapping";
/**
* An invalid keyword alias definition has been encountered.
*/
const INVALID_KEYWORD_ALIAS = "invalid keyword alias";
/**
* An @type member in a term definition was encountered whose value
* could not be expanded to an absolute IRI.
*/
const INVALID_TYPE_MAPPING = "invalid type mapping";
/**
* An @language member in a term definition was encountered whose
* value was neither a string nor null and thus invalid.
*/
const INVALID_LANGUAGE_MAPPING = "invalid language mapping";
/**
* Two properties which expand to the same keyword have been detected.
* This might occur if a keyword and an alias thereof are used at the
* same time.
*/
const COLLIDING_KEYWORDS = "colliding keywords";
/**
* An @container member was encountered whose value was not one of
* the following strings: @list, @set, or @index.
*/
const INVALID_CONTAINER_MAPPING = "invalid container mapping";
/**
* An invalid value for an @type member has been detected, i.e., the
* value was neither a string nor an array of strings.
*/
const INVALID_TYPE_VALUE = "invalid type value";
/**
* A value object with disallowed members has been detected.
*/
const INVALID_VALUE_OBJECT = "invalid value object";
/**
* An invalid value for the @value member of a value object has been
* detected, i.e., it is neither a scalar nor null.
*/
const INVALID_VALUE_OBJECT_VALUE = "invalid value object value";
/**
* A language-tagged string with an invalid language value was detected.
*/
const INVALID_LANGUAGE_TAGGED_STRING = "invalid language-tagged string";
/**
* A number, true, or false with an associated language tag was detected.
*/
const INVALID_LANGUAGE_TAGGED_VALUE = "invalid language-tagged value";
/**
* A typed value with an invalid type was detected.
*/
const INVALID_TYPED_VALUE = "invalid typed value";
/**
* A set object or list object with disallowed members has been detected.
*/
const INVALID_SET_OR_LIST_OBJECT = "invalid set or list object";
/**
* An invalid value in a language map has been detected. It has to be
* a string or an array of strings.
*/
const INVALID_LANGUAGE_MAP_VALUE = "invalid language map value";
/**
* The compacted document contains a list of lists as multiple lists
* have been compacted to the same term.
*/
const COMPACTION_TO_LIST_OF_LISTS = "compaction to list of lists";
/**
* An invalid reverse property map has been detected. No keywords apart
* from @context are allowed in reverse property maps.
*/
const INVALID_REVERSE_PROPERTY_MAP = "invalid reverse property map";
/**
* An invalid value for an @reverse member has been detected, i.e., the
* value was not a JSON object.
*/
const INVALID_REVERSE_VALUE = "invalid @reverse value";
/**
* An invalid value for a reverse property has been detected. The value
* of an inverse property must be a node object.
*/
const INVALID_REVERSE_PROPERTY_VALUE = "invalid reverse property value";
/**
* The JSON-LD snippet that triggered the error
*
* @var null|string
*/
private $snippet;
/**
* The document that triggered the error
*
* @var null|string
*/
private $document;
/**
* The raw error message (containing place-holders)
*
* @var string
*/
private $rawMessage;
/**
* Constructor.
*
* @param string $code The error code
* @param null|string $message The error message
* @param null|mixed $snippet The code snippet
* @param null|string $document The document that triggered the error
* @param null|\Exception $previous The previous exception
*/
public function __construct($code, $message = null, $snippet = null, $document = null, \Exception $previous = null)
{
$this->code = $code;
$this->document = $document;
$this->snippet = ($snippet) ? JsonLD::toString($snippet) : $snippet;
$this->rawMessage = $message;
$this->updateMessage();
parent::__construct($this->message, 0, $previous);
}
/**
* Gets the snippet of code near the error.
*
* @return null|string The snippet of code
*/
public function getSnippet()
{
return $this->snippet;
}
/**
* Gets the document that triggered the error
*
* @return null|string The document that triggered the error
*/
public function getParsedFile()
{
return $this->document;
}
/**
* Updates the exception message by including the file name if available.
*/
private function updateMessage()
{
$this->message = $this->rawMessage;
$dot = false;
if ('.' === substr($this->message, -1)) {
$this->message = substr($this->message, 0, -1);
$dot = true;
}
if (null !== $this->document) {
$this->message .= sprintf(' in %s', $this->document);
}
if ($this->snippet) {
$this->message .= sprintf(' (near %s)', $this->snippet);
}
if ($dot) {
$this->message .= '.';
}
}
}

View File

@@ -0,0 +1,197 @@
<?php
/*
* (c) Markus Lanthaler <mail@markus-lanthaler.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace ML\JsonLD;
use ML\JsonLD\Exception\JsonLdException;
use ML\IRI\IRI;
/**
* The FileGetContentsLoader loads remote documents by calling file_get_contents
*
* @author Markus Lanthaler <mail@markus-lanthaler.com>
*/
class FileGetContentsLoader implements DocumentLoaderInterface
{
/**
* {@inheritdoc}
*/
public function loadDocument($url)
{
// if input looks like a file, try to retrieve it
$input = trim($url);
if (false === (isset($input[0]) && ("{" === $input[0]) || ("[" === $input[0]))) {
$remoteDocument = new RemoteDocument($url);
$streamContextOptions = array(
'method' => 'GET',
'header' => "Accept: application/ld+json, application/json; q=0.9, */*; q=0.1\r\n"
. "User-Agent: lanthaler JsonLD\r\n",
'timeout' => Processor::REMOTE_TIMEOUT
);
$context = stream_context_create(array(
'http' => $streamContextOptions,
'https' => $streamContextOptions
));
$httpHeadersOffset = 0;
stream_context_set_params($context, array('notification' =>
function ($code, $severity, $msg, $msgCode, $bytesTx, $bytesMax) use (
&$remoteDocument, &$http_response_header, &$httpHeadersOffset
) {
if ($code === STREAM_NOTIFY_MIME_TYPE_IS) {
$remoteDocument->mediaType = $msg;
} elseif ($code === STREAM_NOTIFY_REDIRECTED) {
$remoteDocument->documentUrl = $msg;
$remoteDocument->mediaType = null;
$httpHeadersOffset = isset($http_response_header) ? count($http_response_header) : 0;
}
}
));
if (false === ($input = @file_get_contents($url, false, $context))) {
throw new JsonLdException(
JsonLdException::LOADING_DOCUMENT_FAILED,
sprintf('Unable to load the remote document "%s".', $url),
$http_response_header
);
}
// Extract HTTP Link headers
$linkHeaderValues = array();
if (is_array($http_response_header)) {
for ($i = count($http_response_header) - 1; $i > $httpHeadersOffset; $i--) {
if (0 === substr_compare($http_response_header[$i], 'Link:', 0, 5, true)) {
$value = substr($http_response_header[$i], 5);
$linkHeaderValues[] = $value;
}
}
}
$linkHeaderValues = $this->parseLinkHeaders($linkHeaderValues, new IRI($url));
$contextLinkHeaders = array_filter($linkHeaderValues, function ($link) {
return (isset($link['rel'])
&& in_array('http://www.w3.org/ns/json-ld#context', explode(' ', $link['rel'])));
});
if (count($contextLinkHeaders) === 1) {
$remoteDocument->contextUrl = $contextLinkHeaders[0]['uri'];
} elseif (count($contextLinkHeaders) > 1) {
throw new JsonLdException(
JsonLdException::MULTIPLE_CONTEXT_LINK_HEADERS,
'Found multiple contexts in HTTP Link headers',
$http_response_header
);
}
// If we got a media type, we verify it
if ($remoteDocument->mediaType) {
// Drop any media type parameters such as profiles
if (false !== ($pos = strpos($remoteDocument->mediaType, ';'))) {
$remoteDocument->mediaType = substr($remoteDocument->mediaType, 0, $pos);
}
$remoteDocument->mediaType = trim($remoteDocument->mediaType);
if ('application/ld+json' === $remoteDocument->mediaType) {
$remoteDocument->contextUrl = null;
} else {
// If the Media type was not as expected, check to see if the desired content type
// is being offered in a Link header (this is what schema.org now does).
$altLinkHeaders = array_filter($linkHeaderValues, function ($link) {
return (isset($link['rel']) && isset($link['type'])
&& ($link['rel'] === 'alternate') && ($link['type'] === 'application/ld+json'));
});
// The spec states 'A response MUST NOT contain more than one HTTP Link Header
// using the alternate link relation with type="application/ld+json"'
if (count($altLinkHeaders) === 1) {
return $this->loadDocument($altLinkHeaders[0]['uri']);
} elseif (count($altLinkHeaders) > 1) {
throw new JsonLdException(
JsonLdException::LOADING_DOCUMENT_FAILED,
'Received multiple alternate link headers'
);
}
if (('application/json' !== $remoteDocument->mediaType) &&
(0 !== substr_compare($remoteDocument->mediaType, '+json', -5))) {
throw new JsonLdException(
JsonLdException::LOADING_DOCUMENT_FAILED,
'Invalid media type',
$remoteDocument->mediaType
);
}
}
}
$remoteDocument->document = Processor::parse($input);
return $remoteDocument;
}
return new RemoteDocument($url, Processor::parse($input));
}
/**
* Parse HTTP Link headers
*
* @param array $values An array of HTTP Link headers.
* @param IRI $baseIri The document's URL (used to expand relative URLs to absolutes).
*
* @return array A structured representation of the Link header values.
*
* @internal Do not use this method directly, it's only temporarily accessible for testing.
*/
public function parseLinkHeaders(array $values, IRI $baseIri)
{
// Separate multiple links contained in a single header value
for ($i = 0, $total = count($values); $i < $total; $i++) {
if (strpos($values[$i], ',') !== false) {
foreach (preg_split('/,(?=([^"]*"[^"]*")*[^"]*$)/', $values[$i]) as $v) {
$values[] = trim($v);
}
unset($values[$i]);
}
}
$contexts = $matches = array();
$trimWhitespaceCallback = function ($str) {
return trim($str, "\"' \n\t");
};
// Split the header in key-value pairs
$result = array();
foreach ($values as $val) {
$part = array();
foreach (preg_split('/;(?=([^"]*"[^"]*")*[^"]*$)/', $val) as $kvp) {
preg_match_all('/<[^>]+>|[^=]+/', $kvp, $matches);
$pieces = array_map($trimWhitespaceCallback, $matches[0]);
if (count($pieces) > 1) {
$part[$pieces[0]] = $pieces[1];
} elseif (count($pieces) === 1) {
$part['uri'] = (string) $baseIri->resolve(trim($pieces[0], '<> '));
}
}
if (!empty($part)) {
$result[] = $part;
}
}
return $result;
}
}

273
vendor/ml/json-ld/Graph.php vendored Normal file
View File

@@ -0,0 +1,273 @@
<?php
/*
* (c) Markus Lanthaler <mail@markus-lanthaler.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace ML\JsonLD;
use ML\IRI\IRI;
/**
* A Graph represents a JSON-LD graph.
*
* @author Markus Lanthaler <mail@markus-lanthaler.com>
*/
class Graph implements GraphInterface, JsonLdSerializable
{
/**
* @var DocumentInterface The document this graph belongs to.
*/
private $document;
/**
* @var array An associative array holding all nodes in the graph
*/
protected $nodes = array();
/**
* A term map containing terms/prefixes mapped to IRIs. This is similar
* to a JSON-LD context but ignores all definitions except the IRI.
*
* @var array
*/
protected $termMap = array();
/**
* @var int Blank node counter
*/
private $blankNodeCounter = 0;
/**
* Constructor
*
* @param null|DocumentInterface $document The document the graph belongs to.
*/
public function __construct(DocumentInterface $document = null)
{
$this->document = $document;
}
/**
* {@inheritdoc}
*/
public function createNode($id = null, $preserveBnodeId = false)
{
if (!is_string($id) || (!$preserveBnodeId && ('_:' === substr($id, 0, 2)))) {
$id = $this->createBlankNodeId();
} else {
$id = (string) $this->resolveIri($id);
if (isset($this->nodes[$id])) {
return $this->nodes[$id];
}
}
return $this->nodes[$id] = new Node($this, $id);
}
/**
* {@inheritdoc}
*/
public function removeNode(NodeInterface $node)
{
if ($node->getGraph() === $this) {
$node->removeFromGraph();
}
$id = $node->getId();
if (!$node->isBlankNode()) {
$id = (string) $this->resolveIri($id);
}
unset($this->nodes[$id]);
return $this;
}
/**
* {@inheritdoc}
*/
public function getNodes()
{
return array_values($this->nodes);
}
/**
* {@inheritdoc}
*/
public function getNode($id)
{
if (!((strlen($id) >= 2) && ('_:' === substr($id, 0, 2)))) {
$id = (string) $this->resolveIri($id);
}
return isset($this->nodes[$id])
? $this->nodes[$id]
: null;
}
/**
* {@inheritdoc}
*/
public function getNodesByType($type)
{
if (is_string($type)) {
if (null === ($type = $this->getNode($type))) {
return array();
}
}
return $type->getNodesWithThisType();
}
/**
* {@inheritdoc}
*/
public function containsNode($id)
{
$node = $id;
if ($node instanceof Node) {
$id = $node->getId();
}
if ((null === $id) || !is_string($id)) {
return false;
}
if ((strlen($id) >= 2) && ('_:' === substr($id, 0, 2))) {
if (isset($this->nodes[$id]) && ($node === $this->nodes[$id])) {
return true;
}
return false;
}
$id = (string) $this->resolveIri($id);
return isset($this->nodes[$id]);
}
/**
* {@inheritdoc}
*/
public function getDocument()
{
return $this->document;
}
/**
* {@inheritdoc}
*/
public function removeFromDocument()
{
$doc = $this->document;
$this->document = null;
$doc->removeGraph($this);
return $this;
}
/**
* {@inheritdoc}
*/
public function merge(GraphInterface $graph)
{
$nodes = $graph->getNodes();
$bnodeMap = array();
foreach ($nodes as $node) {
if ($node->isBlankNode()) {
if (false === isset($bnodeMap[$node->getId()])) {
$bnodeMap[$node->getId()] = $this->createNode();
}
$n = $bnodeMap[$node->getId()];
} else {
$n = $this->createNode($node->getId());
}
foreach ($node->getProperties() as $property => $values) {
if (false === is_array($values)) {
$values = array($values);
}
foreach ($values as $val) {
if ($val instanceof NodeInterface) {
// If the value is another node, we just need to
// create a reference to the corresponding node
// in this graph. The properties will be merged
// in the outer loop
if ($val->isBlankNode()) {
if (false === isset($bnodeMap[$val->getId()])) {
$bnodeMap[$val->getId()] = $this->createNode();
}
$val = $bnodeMap[$val->getId()];
} else {
$val = $this->createNode($val->getId());
}
} elseif (is_object($val)) {
// Clone typed values and language-tagged strings
$val = clone $val;
}
$n->addPropertyValue($property, $val);
}
}
}
return $this;
}
/**
* {@inheritdoc}
*/
public function toJsonLd($useNativeTypes = true)
{
// Bring nodes into a deterministic order
$nodes = $this->nodes;
ksort($nodes);
$nodes = array_values($nodes);
$serializeNode = function ($node) use ($useNativeTypes) {
return $node->toJsonLd($useNativeTypes);
};
return array_map($serializeNode, $nodes);
}
/**
* Create a new blank node identifier unique to the document.
*
* @return string The new blank node identifier.
*/
protected function createBlankNodeId()
{
return '_:b' . $this->blankNodeCounter++;
}
/**
* Resolves an IRI against the document's IRI
*
* If the graph isn't attached to a document or the document's IRI is
* not set, the IRI is returned as-is.
*
* @param string|IRI $iri The (relative) IRI to resolve
*
* @return IRI The resolved IRI.
*/
protected function resolveIri($iri)
{
if (null === $this->document) {
$base = new IRI();
} else {
$base = $this->document->getIri(true);
}
return $base->resolve($iri);
}
}

117
vendor/ml/json-ld/GraphInterface.php vendored Normal file
View File

@@ -0,0 +1,117 @@
<?php
/*
* (c) Markus Lanthaler <mail@markus-lanthaler.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace ML\JsonLD;
/**
* JSON-LD graph interface
*
* @author Markus Lanthaler <mail@markus-lanthaler.com>
*/
interface GraphInterface
{
/**
* Creates a new node which is linked to this document
*
* If a blank node identifier or an invalid ID is passed, the ID will be
* ignored and a new blank node identifier unique to the document is
* created for the node.
*
* If there exists already a node with the passed ID in the document,
* that node will be returned instead of creating a new one.
*
* @param null|string $id The ID of the node.
* @param bool $preserveBnodeId If set to false, blank nodes are
* relabeled to avoid collisions;
* otherwise the blank node identifier
* is preserved.
*
* @return Node The newly created node.
*/
public function createNode($id = null, $preserveBnodeId = false);
/**
* Removes a node from the document
*
* This will also eliminate all references to the node within the
* document.
*
* @param NodeInterface $node The node to remove from the document.
*
* @return self
*/
public function removeNode(NodeInterface $node);
/**
* Get all nodes
*
* @return Node[] Returns an array containing all nodes defined in the
* document.
*/
public function getNodes();
/**
* Get a node by ID
*
* @param string $id The ID of the node to retrieve.
*
* @return Node|null Returns the node if found; null otherwise.
*/
public function getNode($id);
/**
* Get nodes by type
*
* @param string|Node $type The type
*
* @return Node[] Returns an array containing all nodes of the specified
* type in the document.
*/
public function getNodesByType($type);
/**
* Check whether the document already contains a node with the
* specified ID
*
* @param string|Node $id The node ID to check. Blank node identifiers
* will always return false except a node instance
* which is part of the document will be passed
* instead of a string.
*
* @return bool Returns true if the document contains a node with the
* specified ID; false otherwise.
*/
public function containsNode($id);
/**
* Get the document the node belongs to
*
* @return null|DocumentInterface Returns the document the node belongs
* to or null if the node doesn't belong
* to any document.
*/
public function getDocument();
/**
* Removes the graph from the document
*
* @return self
*/
public function removeFromDocument();
/**
* Merges the specified graph into the current graph
*
* @param GraphInterface $graph The graph that should be merged into the
* current graph.
*
* @return self
*/
public function merge(GraphInterface $graph);
}

692
vendor/ml/json-ld/JsonLD.php vendored Normal file
View File

@@ -0,0 +1,692 @@
<?php
/*
* (c) Markus Lanthaler <mail@markus-lanthaler.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace ML\JsonLD;
use stdClass as JsonObject;
use ML\JsonLD\Exception\JsonLdException;
use ML\JsonLD\Exception\InvalidQuadException;
use ML\IRI\IRI;
/**
* JsonLD
*
* JsonLD implements the algorithms defined by the
* {@link http://www.w3.org/TR/json-ld-api/ JSON-LD 1.0 API and Processing Algorithms specification}.
* Its interface is, apart from the usage of Promises, exactly the same as the one
* defined by the specification.
*
* Furthermore, it implements an enhanced version of the
* {@link http://json-ld.org/spec/latest/json-ld-framing/ JSON-LD Framing 1.0 draft}
* and an object-oriented interface to access and manipulate JSON-LD documents.
*
* @api
*
* @author Markus Lanthaler <mail@markus-lanthaler.com>
*/
class JsonLD
{
/** Identifier for the default graph */
const DEFAULT_GRAPH = '@default';
/** Identifier for the merged graph */
const MERGED_GRAPH = '@merged';
private static $documentLoader = null;
/**
* Load and parse a JSON-LD document
*
* The document can be supplied directly as string, by passing a file
* path, or by passing a URL.
*
* Usage:
*
* $document = JsonLD::getDocument('document.jsonld');
* print_r($document->getGraphNames());
*
* It is possible to configure the processing by setting the options
* parameter accordingly. Available options are:
*
* <dl>
* <dt>base</dt>
* <dd>The base IRI of the input document.</dd>
*
* <dt>expandContext</dt>
* <dd>An optional context to use additionally to the context embedded
* in input when expanding the input.</dd>
*
* <dt>documentFactory</dt>
* <dd>The document factory.</dd>
*
* <dt>documentLoader</dt>
* <dd>The document loader.</dd>
* </dl>
*
* The options parameter might be passed as associative array or as
* object.
*
* @param string|JsonObject|array $input The JSON-LD document to process.
* @param null|array|JsonObject $options Options to configure the processing.
*
* @return Document The parsed JSON-LD document.
*
* @throws JsonLdException
*
* @api
*/
public static function getDocument($input, $options = null)
{
$options = self::mergeOptions($options);
$input = self::expand($input, $options);
$processor = new Processor($options);
return $processor->getDocument($input);
}
/**
* Expand a JSON-LD document
*
* The document can be supplied directly as string, by passing a file
* path, or by passing a URL.
*
* Usage:
*
* $expanded = JsonLD::expand('document.jsonld');
* print_r($expanded);
*
* It is possible to configure the expansion process by setting the options
* parameter accordingly. Available options are:
*
* <dl>
* <dt>base</dt>
* <dd>The base IRI of the input document.</dd>
*
* <dt>expandContext</dt>
* <dd>An optional context to use additionally to the context embedded
* in input when expanding the input.</dd>
*
* <dt>documentLoader</dt>
* <dd>The document loader.</dd>
* </dl>
*
* The options parameter might be passed as associative array or as
* object.
*
* @param string|JsonObject|array $input The JSON-LD document to expand.
* @param null|array|JsonObject $options Options to configure the expansion
* process.
*
* @return array The expanded JSON-LD document.
*
* @throws JsonLdException
*
* @api
*/
public static function expand($input, $options = null)
{
$options = self::mergeOptions($options);
$processor = new Processor($options);
$activectx = array('@base' => null);
if (is_string($input)) {
$remoteDocument = $options->documentLoader->loadDocument($input);
$input = $remoteDocument->document;
$activectx['@base'] = new IRI($remoteDocument->documentUrl);
if (null !== $remoteDocument->contextUrl) {
$processor->processContext($remoteDocument->contextUrl, $activectx);
}
}
if ($options->base) {
$activectx['@base'] = $options->base;
}
if (null !== $options->expandContext) {
$processor->processContext($options->expandContext, $activectx);
}
$processor->expand($input, $activectx);
// optimize away default graph (@graph as the only property at the top-level object)
if (is_object($input) && property_exists($input, '@graph') && (1 === count(get_object_vars($input)))) {
$input = $input->{'@graph'};
}
if (false === is_array($input)) {
$input = (null === $input) ? array() : array($input);
}
return $input;
}
/**
* Compact a JSON-LD document according a supplied context
*
* Both the document and the context can be supplied directly as string,
* by passing a file path, or by passing a URL.
*
* Usage:
*
* $compacted = JsonLD::compact('document.jsonld', 'context.jsonld');
* print_r($compacted);
*
* It is possible to configure the compaction process by setting the
* options parameter accordingly. Available options are:
*
* <dl>
* <dt>base</dt>
* <dd>The base IRI of the input document.</dd>
*
* <dt>expandContext</dt>
* <dd>An optional context to use additionally to the context embedded
* in input when expanding the input.</dd>
*
* <dt>optimize</dt>
* <dd>If set to true, the processor is free to optimize the result to
* produce an even compacter representation than the algorithm
* described by the official JSON-LD specification.</dd>
*
* <dt>compactArrays</dt>
* <dd>If set to true, arrays holding just one element are compacted
* to scalars, otherwise the arrays are kept as arrays.</dd>
*
* <dt>documentLoader</dt>
* <dd>The document loader.</dd>
* </dl>
*
* The options parameter might be passed as associative array or as
* object.
*
* @param string|JsonObject|array $input The JSON-LD document to
* compact.
* @param null|string|JsonObject|array $context The context.
* @param null|array|JsonObject $options Options to configure the
* compaction process.
*
* @return JsonObject The compacted JSON-LD document.
*
* @throws JsonLdException
*
* @api
*/
public static function compact($input, $context = null, $options = null)
{
$options = self::mergeOptions($options);
$expanded = self::expand($input, $options);
return self::doCompact($expanded, $context, $options);
}
/**
* Compact a JSON-LD document according a supplied context
*
* In contrast to {@link compact()}, this method assumes that the input
* has already been expanded.
*
* @param array $input The JSON-LD document to
* compact.
* @param null|string|JsonObject|array $context The context.
* @param JsonObject $options Options to configure the
* compaction process.
* @param bool $alwaysGraph If set to true, the resulting
* document will always explicitly
* contain the default graph at
* the top-level.
*
* @return JsonObject The compacted JSON-LD document.
*
* @throws JsonLdException
*/
private static function doCompact($input, $context, $options, $alwaysGraph = false)
{
if (is_string($context)) {
$context = $options->documentLoader->loadDocument($context)->document;
}
if (is_object($context) && property_exists($context, '@context')) {
$context = $context->{'@context'};
}
if (is_object($context) && (0 === count(get_object_vars($context)))) {
$context = null;
} elseif (is_array($context) && (0 === count($context))) {
$context = null;
}
$activectx = array('@base' => $options->base);
$processor = new Processor($options);
$processor->processContext($context, $activectx);
$inversectx = $processor->createInverseContext($activectx);
$processor->compact($input, $activectx, $inversectx);
$compactedDocument = new JsonObject();
if (null !== $context) {
$compactedDocument->{'@context'} = $context;
}
if ((false === is_array($input)) || (0 === count($input))) {
if (false === $alwaysGraph) {
$compactedDocument = (object) ((array) $compactedDocument + (array) $input);
return $compactedDocument;
}
if (false === is_array($input)) {
$input = array($input);
}
}
$graphKeyword = (isset($inversectx['@graph']['term']))
? $inversectx['@graph']['term']
: '@graph';
$compactedDocument->{$graphKeyword} = $input;
return $compactedDocument;
}
/**
* Flatten a JSON-LD document
*
* Both the document and the context can be supplied directly as string,
* by passing a file path, or by passing a URL.
*
* Usage:
*
* $flattened = JsonLD::flatten('document.jsonld');
* print_r($flattened);
*
* It is possible to configure the flattening process by setting the options
* parameter accordingly. Available options are:
*
* <dl>
* <dt>base</dt>
* <dd>The base IRI of the input document.</dd>
*
* <dt>expandContext</dt>
* <dd>An optional context to use additionally to the context embedded
* in input when expanding the input.</dd>
*
* <dt>graph</dt>
* <dd>The graph whose flattened representation should be returned.
* The default graph is identified by {@link DEFAULT_GRAPH} and the
* merged dataset graph by {@link MERGED_GRAPH}. If <em>null</em> is
* passed, all graphs will be returned.</dd>
*
* <dt>documentLoader</dt>
* <dd>The document loader.</dd>
* </dl>
*
* The options parameter might be passed as associative array or as
* object.
*
* @param string|JsonObject|array $input The JSON-LD document to flatten.
* @param null|string|JsonObject|array $context The context to compact the
* flattened document. If
* <em>null</em> is passed, the
* result will not be compacted.
* @param null|array|JsonObject $options Options to configure the
* flattening process.
*
* @return JsonObject The flattened JSON-LD document.
*
* @throws JsonLdException
*
* @api
*/
public static function flatten($input, $context = null, $options = null)
{
$options = self::mergeOptions($options);
$input = self::expand($input, $options);
$processor = new Processor($options);
$flattened = $processor->flatten($input);
if (null === $context) {
return $flattened;
}
return self::doCompact($flattened, $context, $options, true);
}
/**
* Convert a JSON-LD document to RDF quads
*
* The document can be supplied directly as string, by passing a file
* path, or by passing a URL.
*
* Usage:
*
* $quads = JsonLD::toRdf('document.jsonld');
* print_r($quads);
*
* It is possible to configure the extraction process by setting the options
* parameter accordingly. Available options are:
*
* <dl>
* <dt>base</dt>
* <dd>The base IRI of the input document.</dd>
*
* <dt>expandContext</dt>
* <dd>An optional context to use additionally to the context embedded
* in input when expanding the input.</dd>
*
* <dt>documentLoader</dt>
* <dd>The document loader.</dd>
* </dl>
*
* The options parameter might be passed as associative array or as
* object.
*
* @param string|JsonObject|array $input The JSON-LD document to expand.
* @param null|array|JsonObject $options Options to configure the expansion
* process.
*
* @return Quad[] The extracted quads.
*
* @throws JsonLdException
*
* @api
*/
public static function toRdf($input, $options = null)
{
$options = self::mergeOptions($options);
$expanded = self::expand($input, $options);
$processor = new Processor($options);
return $processor->toRdf($expanded);
}
/**
* Convert an array of RDF quads to a JSON-LD document
*
* Usage:
*
* $document = JsonLD::fromRdf($quads);
* print(JsonLD::toString($document, true));
*
* It is possible to configure the conversion process by setting the options
* parameter accordingly. Available options are:
*
* <dl>
* <dt>base</dt>
* <dd>The base IRI of the input document.</dd>
*
* <dt>useNativeTypes</dt>
* <dd>If set to true, native types are used for <em>xsd:integer</em>,
* <em>xsd:double</em>, and <em>xsd:boolean</em>; otherwise,
* typed strings will be used instead.</dd>
*
* <dt>useRdfType</dt>
* <dd>If set to true, <em>rdf:type</em> will be used instead of <em>@type</em>
*
* <dt>documentLoader</dt>
* <dd>The document loader.</dd>
* </dl>
*
* The options parameter might be passed as associative array or as
* object.
*
* @param Quad[] $quads Array of quads.
* @param null|array|JsonObject $options Options to configure the expansion
* process.
*
* @return array The JSON-LD document in expanded form.
*
* @throws InvalidQuadException If an invalid quad was detected.
* @throws JsonLdException If converting the quads to a JSON-LD document failed.
*
* @api
*/
public static function fromRdf(array $quads, $options = null)
{
$options = self::mergeOptions($options);
$processor = new Processor($options);
return $processor->fromRdf($quads);
}
/**
* Frame a JSON-LD document according a supplied frame
*
* Both the document and the frame can be supplied directly as string,
* by passing a file path, or by passing a URL.
*
* Usage:
*
* $result = JsonLD::frame('document.jsonld', 'frame.jsonldf');
* print_r($compacted);
*
* It is possible to configure the framing process by setting the options
* parameter accordingly. Available options are:
*
* <dl>
* <dt>base</dt>
* <dd>The base IRI of the input document.</dd>
*
* <dt>expandContext</dt>
* <dd>An optional context to use additionally to the context embedded
* in input when expanding the input.</dd>
*
* <dt>optimize</dt>
* <dd>If set to true, the processor is free to optimize the result to
* produce an even compacter representation than the algorithm
* described by the official JSON-LD specification.</dd>
*
* <dt>compactArrays</dt>
* <dd>If set to true, arrays holding just one element are compacted
* to scalars, otherwise the arrays are kept as arrays.</dd>
*
* <dt>documentLoader</dt>
* <dd>The document loader.</dd>
* </dl>
*
* The options parameter might be passed as associative array or as
* object.
*
* @param string|JsonObject|array $input The JSON-LD document to compact.
* @param string|JsonObject $frame The frame.
* @param null|array|JsonObject $options Options to configure the framing
* process.
*
* @return JsonObject The framed JSON-LD document.
*
* @throws JsonLdException
*
* @api
*/
public static function frame($input, $frame, $options = null)
{
$options = self::mergeOptions($options);
$input = self::expand($input, $options);
$frame = (is_string($frame))
? $options->documentLoader->loadDocument($frame)->document
: $frame;
if (false === is_object($frame)) {
throw new JsonLdException(
JsonLdException::UNSPECIFIED,
'Invalid frame detected. It must be an object.',
$frame
);
}
$processor = new Processor($options);
// Store the frame's context as $frame gets modified
$frameContext = new JsonObject();
if (property_exists($frame, '@context')) {
$frameContext->{'@context'} = $frame->{'@context'};
}
// Expand the frame
$processor->expand($frame, array(), null, true);
// and optimize away default graph (@graph as the only property at the top-level object)
if (is_object($frame) && property_exists($frame, '@graph') && (1 === count(get_object_vars($frame)))) {
$frame = $frame->{'@graph'};
}
if (false === is_array($frame)) {
$frame = array($frame);
}
// Frame the input document
$result = $processor->frame($input, $frame);
// Compact the result using the frame's active context
return self::doCompact($result, $frameContext, $options, true);
}
/**
* Convert the PHP structure returned by the various processing methods
* to a string
*
* Usage:
*
* $compacted = JsonLD::compact('document.jsonld', 'context.jsonld');
* $prettyString = JsonLD::toString($compacted, true);
* print($prettyString);
*
* @param mixed $value The value to convert.
* @param bool $pretty Use whitespace in returned string to format it
* (this just works in PHP >=5.4)?
*
* @return string
*/
public static function toString($value, $pretty = false)
{
$options = 0;
if (PHP_VERSION_ID >= 50400) {
$options |= JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE;
if ($pretty) {
$options |= JSON_PRETTY_PRINT;
}
return json_encode($value, $options);
} else {
$result = json_encode($value);
$result = str_replace('\\/', '/', $result); // unescape slahes
// unescape unicode
return preg_replace_callback(
'/\\\\u([a-f0-9]{4})/',
function ($match) {
return iconv('UCS-4LE', 'UTF-8', pack('V', hexdec($match[1])));
},
$result
);
}
}
/**
* Merge the passed options with the options' default values.
*
* @param null|array|JsonObject $options The options.
*
* @return JsonObject The merged options.
*/
private static function mergeOptions($options)
{
$result = (object) array(
'base' => null,
'expandContext' => null,
'compactArrays' => true,
'optimize' => false,
'graph' => null,
'useNativeTypes' => false,
'useRdfType' => false,
'produceGeneralizedRdf' => false,
'documentFactory' => null,
'documentLoader' => new FileGetContentsLoader()
);
if (is_array($options) || is_object($options)) {
$options = (object) $options;
if (isset($options->{'base'})) {
if (is_string($options->{'base'})) {
$result->base = new IRI($options->{'base'});
} elseif (($options->{'base'} instanceof IRI) && $options->{'base'}->isAbsolute()) {
$result->base = clone $options->{'base'};
} else {
throw new \InvalidArgumentException('The "base" option must be set to null or an absolute IRI.');
}
}
if (property_exists($options, 'compactArrays') && is_bool($options->compactArrays)) {
$result->compactArrays = $options->compactArrays;
}
if (property_exists($options, 'optimize') && is_bool($options->optimize)) {
$result->optimize = $options->optimize;
}
if (property_exists($options, 'graph') && is_string($options->graph)) {
$result->graph = $options->graph;
}
if (property_exists($options, 'useNativeTypes') && is_bool($options->useNativeTypes)) {
$result->useNativeTypes = $options->useNativeTypes;
}
if (property_exists($options, 'useRdfType') && is_bool($options->useRdfType)) {
$result->useRdfType = $options->useRdfType;
}
if (property_exists($options, 'produceGeneralizedRdf') && is_bool($options->produceGeneralizedRdf)) {
$result->produceGeneralizedRdf = $options->produceGeneralizedRdf;
}
if (property_exists($options, 'documentFactory') &&
($options->documentFactory instanceof DocumentFactoryInterface)) {
$result->documentFactory = $options->documentFactory;
}
if (property_exists($options, 'documentLoader') &&
($options->documentLoader instanceof DocumentLoaderInterface)) {
$result->documentLoader = $options->documentLoader;
} elseif (null !== self::$documentLoader) {
$result->documentLoader = self::$documentLoader;
}
if (property_exists($options, 'expandContext')) {
if (is_string($options->expandContext)) {
$result->expandContext = $result->documentLoader->loadDocument($options->expandContext)->document;
} elseif (is_object($options->expandContext)) {
$result->expandContext = $options->expandContext;
}
if (is_object($result->expandContext) && property_exists($result->expandContext, '@context')) {
$result->expandContext = $result->expandContext->{'@context'};
}
}
}
return $result;
}
/**
* Set the default document loader.
*
* It can be overridden in individual operations by setting the
* `documentLoader` option.
*
* @param DocumentLoaderInterface $documentLoader
*/
public static function setDefaultDocumentLoader(DocumentLoaderInterface $documentLoader)
{
self::$documentLoader = $documentLoader;
}
}

View File

@@ -0,0 +1,38 @@
<?php
/*
* (c) Markus Lanthaler <mail@markus-lanthaler.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace ML\JsonLD;
/**
* The JsonLdSerializable interface
*
* Objects implementing JsonLdSerializable can be serialized to JSON-LD.
*
* @author Markus Lanthaler <mail@markus-lanthaler.com>
*/
interface JsonLdSerializable
{
/**
* Convert to expanded and flattened JSON-LD
*
* The result can then be serialized to JSON-LD by {@see JsonLD::toString()}.
*
* @param boolean $useNativeTypes If set to true, native types are used
* for xsd:integer, xsd:double, and
* xsd:boolean, otherwise typed strings
* will be used instead.
*
* @return mixed Returns data which can be serialized by
* {@see JsonLD::toString()} (which is a value of any type
* other than a resource) to expanded JSON-LD.
*
* @see JsonLD::toString()
*/
public function toJsonLd($useNativeTypes = true);
}

19
vendor/ml/json-ld/LICENSE vendored Normal file
View File

@@ -0,0 +1,19 @@
Copyright (c) 2012-2016 Markus Lanthaler
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.

View File

@@ -0,0 +1,95 @@
<?php
/*
* (c) Markus Lanthaler <mail@markus-lanthaler.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace ML\JsonLD;
use stdClass as JsonObject;
/**
* A LanguageTaggedString is a string which is tagged with a language.
*
* @author Markus Lanthaler <mail@markus-lanthaler.com>
*/
final class LanguageTaggedString extends Value
{
/**
* The language code associated with the string. Language codes are tags
* according to {@link http://tools.ietf.org/html/bcp47 BCP47}.
*
* @var string
*/
private $language;
/**
* Constructor
*
* @param string $value The string's value.
* @param string $language The string's language.
*/
public function __construct($value, $language)
{
$this->setValue($value);
$this->setLanguage($language);
}
/**
* Set the language
*
* @param string $language The language.
*
* @return self
*
* @throws \InvalidArgumentException If the language is not a string. No
* further checks are currently done.
*/
public function setLanguage($language)
{
if (!is_string($language)) {
throw new \InvalidArgumentException('language must be a string.');
}
$this->language = $language;
return $this;
}
/**
* Get the language
*
* @return string The language.
*/
public function getLanguage()
{
return $this->language;
}
/**
* {@inheritdoc}
*/
public function toJsonLd($useNativeTypes = true)
{
$result = new JsonObject();
$result->{'@value'} = $this->value;
$result->{'@language'} = $this->language;
return $result;
}
/**
* {@inheritdoc}
*/
public function equals($other)
{
if (get_class($this) !== get_class($other)) {
return false;
}
return ($this->value === $other->value) && ($this->language === $other->language);
}
}

176
vendor/ml/json-ld/NQuads.php vendored Normal file
View File

@@ -0,0 +1,176 @@
<?php
/*
* (c) Markus Lanthaler <mail@markus-lanthaler.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace ML\JsonLD;
use ML\JsonLD\Exception\InvalidQuadException;
use ML\IRI\IRI;
/**
* NQuads serializes quads to the NQuads format
*
* @author Markus Lanthaler <mail@markus-lanthaler.com>
*/
class NQuads implements QuadSerializerInterface, QuadParserInterface
{
/**
* {@inheritdoc}
*/
public function serialize(array $quads)
{
$result = '';
foreach ($quads as $quad) {
$result .= ('_' === $quad->getSubject()->getScheme())
? $quad->getSubject()
: '<' . $quad->getSubject() . '>';
$result .= ' ';
$result .= ('_' === $quad->getProperty()->getScheme())
? $quad->getProperty()
: '<' . $quad->getProperty() . '>';
$result .= ' ';
if ($quad->getObject() instanceof IRI) {
$result .= ('_' === $quad->getObject()->getScheme())
? $quad->getObject()
: '<' . $quad->getObject() . '>';
} else {
$result .= '"' . str_replace(
array("\n", '"'),
array('\n', '\"'),
$quad->getObject()->getValue()) . '"';
$result .= ($quad->getObject() instanceof TypedValue)
? (RdfConstants::XSD_STRING === $quad->getObject()->getType())
? ''
: '^^<' . $quad->getObject()->getType() . '>'
: '@' . $quad->getObject()->getLanguage();
}
$result .= ' ';
if ($quad->getGraph()) {
$result .= ('_' === $quad->getGraph()->getScheme())
? $quad->getGraph() :
'<' . $quad->getGraph() . '>';
$result .= ' ';
}
$result .= ".\n";
}
return $result;
}
/**
* {@inheritdoc}
*
* This method is heavily based on DigitalBazaar's implementation used
* in their {@link https://github.com/digitalbazaar/php-json-ld php-json-ld}.
*
* @throws InvalidQuadException If an invalid quad that can't be parsed is
* encountered.
*/
public function parse($input)
{
// define partial regexes
$iri = '(?:<([^>]*)>)';
// blank node labels based on https://www.w3.org/TR/n-quads/#BNodes
$bnode = '(_:(?:[A-Za-z0-9_]|[A-Za-z0-9_][A-Za-z0-9_\-.]*[A-Za-z0-9_\-]))';
$plain = '"([^"\\\\]*(?:\\\\.[^"\\\\]*)*)"';
$datatype = "\\^\\^$iri";
$language = '(?:@([a-z]+(?:-[a-z0-9]+)*))';
$literal = "(?:$plain(?:$datatype|$language)?)";
$ws = '[ \\t]';
$comment = "#.*";
$subject = "(?:$iri|$bnode)$ws+";
$property = "$iri$ws+";
$object = "(?:$iri|$bnode|$literal)";
$graph = "$ws+(?:$iri|$bnode)";
// full regexes
$eoln = '/(?:(\r\n)|[\n\r])/';
$quadRegex = "/^$ws*$subject$property$object$graph?$ws*.$ws*$/";
$ignoreRegex = "/^$ws*(?:$comment)?$/";
// build RDF statements
$statements = array();
// split N-Quad input into lines
$lines = preg_split($eoln, $input);
$line_number = 0;
foreach ($lines as $line) {
$line_number++;
// skip empty lines
if (preg_match($ignoreRegex, $line)) {
continue;
}
// parse quad
if (!preg_match($quadRegex, $line, $match)) {
throw new InvalidQuadException(
sprintf(
'Error while parsing N-Quads. Invalid quad in line %d: %s',
$line_number,
$line
),
$line
);
}
// get subject
if ($match[1] !== '') {
$subject = new IRI($match[1]);
} else {
$subject = new IRI($match[2]);
}
// get property
$property = new IRI($match[3]);
// get object
if ($match[4] !== '') {
$object = new IRI($match[4]); // IRI
} elseif ($match[5] !== '') {
$object = new IRI($match[5]); // bnode
} else {
$unescaped = str_replace(
array('\"', '\t', '\n', '\r', '\\\\'),
array('"', "\t", "\n", "\r", '\\'),
$match[6]
);
if (isset($match[7]) && $match[7] !== '') {
$object = new TypedValue($unescaped, $match[7]);
} elseif (isset($match[8]) && $match[8] !== '') {
$object = new LanguageTaggedString($unescaped, $match[8]);
} else {
$object = new TypedValue($unescaped, RdfConstants::XSD_STRING);
}
}
// get graph
$graph = null;
if (isset($match[9]) && $match[9] !== '') {
$graph = new IRI($match[9]);
} elseif (isset($match[10]) && $match[10] !== '') {
$graph = new IRI($match[10]);
}
$quad = new Quad($subject, $property, $object, $graph);
// TODO Make sure that quads are unique??
$statements[] = $quad;
}
return $statements;
}
}

509
vendor/ml/json-ld/Node.php vendored Normal file
View File

@@ -0,0 +1,509 @@
<?php
/*
* (c) Markus Lanthaler <mail@markus-lanthaler.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace ML\JsonLD;
use stdClass as JsonObject;
/**
* A Node represents a node in a JSON-LD graph.
*
* @author Markus Lanthaler <mail@markus-lanthaler.com>
*/
class Node implements NodeInterface, JsonLdSerializable
{
/** The @type constant. */
const TYPE = '@type';
/**
* @var GraphInterface The graph the node belongs to.
*/
private $graph;
/**
* @var string The ID of the node
*/
private $id;
/**
* @var array An associative array holding all properties of the node except it's ID
*/
private $properties = array();
/**
* An associative array holding all reverse properties of this node, i.e.,
* a pointers to all nodes that link to this node.
*
* @var array
*/
private $revProperties = array();
/**
* Constructor
*
* @param GraphInterface $graph The graph the node belongs to.
* @param null|string $id The ID of the node.
*/
public function __construct(GraphInterface $graph, $id = null)
{
$this->graph = $graph;
$this->id = $id;
}
/**
* {@inheritdoc}
*/
public function getId()
{
return $this->id;
}
/**
* {@inheritdoc}
*/
public function setType($type)
{
if ((null !== $type) && !($type instanceof NodeInterface)) {
if (is_array($type)) {
foreach ($type as $val) {
if ((null !== $val) && !($val instanceof NodeInterface)) {
throw new \InvalidArgumentException('type must be null, a Node, or an array of Nodes');
}
}
} else {
throw new \InvalidArgumentException('type must be null, a Node, or an array of Nodes');
}
}
$this->setProperty(self::TYPE, $type);
return $this;
}
/**
* {@inheritdoc}
*/
public function addType(NodeInterface $type)
{
$this->addPropertyValue(self::TYPE, $type);
return $this;
}
/**
* {@inheritdoc}
*/
public function removeType(NodeInterface $type)
{
$this->removePropertyValue(self::TYPE, $type);
return $this;
}
/**
* {@inheritdoc}
*/
public function getType()
{
return $this->getProperty(self::TYPE);
}
/**
* {@inheritdoc}
*/
public function getNodesWithThisType()
{
if (null === ($nodes = $this->getReverseProperty(self::TYPE))) {
return array();
}
return (is_array($nodes)) ? $nodes : array($nodes);
}
/**
* {@inheritdoc}
*/
public function getGraph()
{
return $this->graph;
}
/**
* {@inheritdoc}
*/
public function removeFromGraph()
{
// Remove other node's properties and reverse properties pointing to
// this node
foreach ($this->revProperties as $property => $nodes) {
foreach ($nodes as $node) {
$node->removePropertyValue($property, $this);
}
}
foreach ($this->properties as $property => $values) {
if (!is_array($values)) {
$values = array($values);
}
foreach ($values as $value) {
if ($value instanceof NodeInterface) {
$this->removePropertyValue($property, $value);
}
}
}
$g = $this->graph;
$this->graph = null;
$g->removeNode($this);
return $this;
}
/**
* {@inheritdoc}
*/
public function isBlankNode()
{
return ((null === $this->id) || ('_:' === substr($this->id, 0, 2)));
}
/**
* {@inheritdoc}
*/
public function setProperty($property, $value)
{
if (null === $value) {
$this->removeProperty($property);
} else {
$this->doMergeIntoProperty((string) $property, array(), $value);
}
return $this;
}
/**
* {@inheritdoc}
*/
public function addPropertyValue($property, $value)
{
$existing = (isset($this->properties[(string) $property]))
? $this->properties[(string) $property]
: array();
if (!is_array($existing)) {
$existing = array($existing);
}
$this->doMergeIntoProperty((string) $property, $existing, $value);
return $this;
}
/**
* Merge a value into a set of existing values.
*
* @param string $property The name of the property.
* @param array $existingValues The existing values.
* @param mixed $value The value to merge into the existing
* values. This MUST NOT be an array.
*
* @throws \InvalidArgumentException If value is an array or an object
* which is neither a language-tagged
* string nor a typed value or a node.
*/
private function doMergeIntoProperty($property, $existingValues, $value)
{
// TODO: Handle lists!
if (null === $value) {
return;
}
if (!$this->isValidPropertyValue($value)) {
throw new \InvalidArgumentException(
'value must be a scalar, a node, a language-tagged string, or a typed value'
);
}
$normalizedValue = $this->normalizePropertyValue($value);
foreach ($existingValues as $existing) {
if ($this->equalValues($existing, $normalizedValue)) {
return;
}
}
$existingValues[] = $normalizedValue;
if (1 === count($existingValues)) {
$existingValues = $existingValues[0];
}
$this->properties[$property] = $existingValues;
if ($normalizedValue instanceof NodeInterface) {
$value->addReverseProperty($property, $this);
}
}
/**
* {@inheritdoc}
*/
public function removeProperty($property)
{
if (!isset($this->properties[(string) $property])) {
return $this;
}
$values = is_array($this->properties[(string) $property])
? $this->properties[(string) $property]
: array($this->properties[(string) $property]);
foreach ($values as $value) {
if ($value instanceof NodeInterface) {
$value->removeReverseProperty((string) $property, $this);
}
}
unset($this->properties[(string) $property]);
return $this;
}
/**
* {@inheritdoc}
*/
public function removePropertyValue($property, $value)
{
if (!$this->isValidPropertyValue($value) || !isset($this->properties[(string) $property])) {
return $this;
}
$normalizedValue = $this->normalizePropertyValue($value);
$values =& $this->properties[(string) $property];
if (!is_array($this->properties[(string) $property])) {
$values = array($values);
}
for ($i = 0, $length = count($values); $i < $length; $i++) {
if ($this->equalValues($values[$i], $normalizedValue)) {
if ($normalizedValue instanceof NodeInterface) {
$normalizedValue->removeReverseProperty((string) $property, $this);
}
unset($values[$i]);
break;
}
}
if (0 === count($values)) {
unset($this->properties[(string) $property]);
return $this;
}
$this->properties[(string) $property] = array_values($values); // re-index the array
if (1 === count($this->properties[(string) $property])) {
$this->properties[(string) $property] = $this->properties[(string) $property][0];
}
}
/**
* {@inheritdoc}
*/
public function getProperties()
{
return $this->properties;
}
/**
* {@inheritdoc}
*/
public function getProperty($property)
{
return (isset($this->properties[(string) $property]))
? $this->properties[(string) $property]
: null;
}
/**
* {@inheritdoc}
*/
public function getReverseProperties()
{
$result = array();
foreach ($this->revProperties as $key => $nodes) {
$result[$key] = array_values($nodes);
}
return $result;
}
/**
* {@inheritdoc}
*/
public function getReverseProperty($property)
{
if (!isset($this->revProperties[(string) $property])) {
return null;
}
$result = array_values($this->revProperties[(string) $property]);
return (1 === count($result))
? $result[0]
: $result;
}
/**
* {@inheritdoc}
*/
public function equals(NodeInterface $other)
{
return $this === $other;
}
/**
* {@inheritdoc}
*/
public function toJsonLd($useNativeTypes = true)
{
$node = new \stdClass();
// Only label blank nodes if other nodes point to it
if ((false === $this->isBlankNode()) || (count($this->getReverseProperties()) > 0)) {
$node->{'@id'} = $this->getId();
}
$properties = $this->getProperties();
foreach ($properties as $prop => $values) {
if (false === is_array($values)) {
$values = array($values);
}
if (self::TYPE === $prop) {
$node->{'@type'} = array();
foreach ($values as $val) {
$node->{'@type'}[] = $val->getId();
}
continue;
}
$node->{$prop} = array();
foreach ($values as $value) {
if ($value instanceof NodeInterface) {
$ref = new \stdClass();
$ref->{'@id'} = $value->getId();
$node->{$prop}[] = $ref;
} elseif (is_object($value)) { // language-tagged string or typed value
$node->{$prop}[] = $value->toJsonLd($useNativeTypes);
} else {
$val = new JsonObject();
$val->{'@value'} = $value;
$node->{$prop}[] = $val;
}
}
}
return $node;
}
/**
* Add a reverse property.
*
* @param string $property The name of the property.
* @param NodeInterface $node The node which has a property pointing
* to this node instance.
*/
protected function addReverseProperty($property, NodeInterface $node)
{
$this->revProperties[$property][$node->getId()] = $node;
}
/**
* Remove a reverse property.
*
* @param string $property The name of the property.
* @param NodeInterface $node The node which has a property pointing
* to this node instance.
*/
protected function removeReverseProperty($property, NodeInterface $node)
{
unset($this->revProperties[$property][$node->getId()]);
if (0 === count($this->revProperties[$property])) {
unset($this->revProperties[$property]);
}
}
/**
* Checks whether a value is a valid property value.
*
* @param mixed $value The value to check.
*
* @return bool Returns true if the value is a valid property value;
* false otherwise.
*/
protected function isValidPropertyValue($value)
{
return (is_scalar($value) ||
(is_object($value) &&
((($value instanceof NodeInterface) && ($value->getGraph() === $this->graph)) ||
($value instanceof Value))));
}
/**
* Normalizes a property value by converting scalars to Value objects.
*
* @param mixed $value The value to normalize.
*
* @return NodeInterface|Value The normalized value.
*/
protected function normalizePropertyValue($value)
{
if (false === is_scalar($value)) {
return $value;
}
return Value::fromJsonLd((object) array('@value' => $value));
}
/**
* Checks whether the two specified values are the same.
*
* Scalars and nodes are checked for identity, value objects for
* equality.
*
* @param mixed $value1 Value 1.
* @param mixed $value2 Value 2.
*
* @return bool Returns true if the two values are equals; otherwise false.
*/
protected function equalValues($value1, $value2)
{
if (gettype($value1) !== gettype($value2)) {
return false;
}
if (is_object($value1) && ($value1 instanceof Value)) {
return $value1->equals($value2);
}
return ($value1 === $value2);
}
}

218
vendor/ml/json-ld/NodeInterface.php vendored Normal file
View File

@@ -0,0 +1,218 @@
<?php
/*
* (c) Markus Lanthaler <mail@markus-lanthaler.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace ML\JsonLD;
/**
* A generic interface for nodes in a JSON-LD graph.
*
* @author Markus Lanthaler <mail@markus-lanthaler.com>
*/
interface NodeInterface
{
/**
* Get ID
*
* @return string|null The ID of the node or null.
*/
public function getId();
/**
* Set the node type
*
* @param null|NodeInterface|array[NodeInterface] The type(s) of this node.
*
* @return self
*
* @throws \InvalidArgumentException If type is not null, a Node or an
* array of Nodes.
*/
public function setType($type);
/**
* Add a type to this node
*
* @param NodeInterface The type to add.
*
* @return self
*/
public function addType(NodeInterface $type);
/**
* Remove a type from this node
*
* @param NodeInterface The type to remove.
*
* @return self
*/
public function removeType(NodeInterface $type);
/**
* Get node type
*
* @return null|NodeInterface|NodeInterface[] Returns the type(s) of this node.
*/
public function getType();
/**
* Get the nodes which have this node as their type
*
* This will return all nodes that link to this Node instance via the
* @type (rdf:type) property.
*
* @return NodeInterface[] Returns the node(s) having this node as their
* type.
*/
public function getNodesWithThisType();
/**
* Get the graph the node belongs to
*
* @return null|GraphInterface Returns the graph the node belongs to or
* null if the node doesn't belong to any graph.
*/
public function getGraph();
/**
* Removes the node from the graph
*
* This will also remove all references to and from other nodes in this
* node's graph.
*
* @return self
*/
public function removeFromGraph();
/**
* Is this node a blank node
*
* A blank node is a node whose identifier has just local meaning. It has
* therefore a node identifier with the prefix <code>_:</code> or no
* identifier at all.
*
* @return bool Returns true if the node is a blank node, otherwise false.
*/
public function isBlankNode();
/**
* Set a property of the node
*
* If the value is or contains a reference to a node which is not part
* of the graph, the referenced node will added to the graph as well.
* If the referenced node is already part of another graph a copy of the
* node will be created and added to the graph.
*
* @param string $property The name of the property.
* @param mixed $value The value of the property. This MUST NOT be
* an array. Use null to remove the property.
*
* @return self
*
* @throws \InvalidArgumentException If value is an array or an object
* which is neither a language-tagged
* string nor a typed value or a node.
*/
public function setProperty($property, $value);
/**
* Adds a value to a property of the node
*
* If the value already exists, it won't be added again, i.e., there
* won't be any duplicate property values.
*
* If the value is or contains a reference to a node which is not part
* of the graph, the referenced node will added to the graph as well.
* If the referenced node is already part of another graph a copy of the
* node will be created and added to the graph.
*
* @param string $property The name of the property.
* @param mixed $value The value of the property. This MUST NOT be
* an array.
*
* @return self
*
* @throws \InvalidArgumentException If value is an array or an object
* which is neither a language-tagged
* string nor a typed value or a node.
*/
public function addPropertyValue($property, $value);
/**
* Removes a property and all it's values
*
* @param string $property The name of the property to remove.
*
* @return self
*/
public function removeProperty($property);
/**
* Removes a property value
*
* @param string $property The name of the property.
* @param mixed $value The value of the property. This MUST NOT be
* an array.
*
* @return self
*/
public function removePropertyValue($property, $value);
/**
* Get the properties of this node
*
* @return array Returns an associative array containing all properties
* of this node. The key is the property name whereas the
* value is the property's value.
*/
public function getProperties();
/**
* Get the value of a property
*
* @param string $property The name of the property.
*
* @return mixed Returns the value of the property or null if the
* property doesn't exist.
*/
public function getProperty($property);
/**
* Get the reverse properties of this node
*
* @return array Returns an associative array containing all reverse
* properties of this node. The key is the property name
* whereas the value is an array of nodes linking to this
* instance via that property.
*/
public function getReverseProperties();
/**
* Get the nodes of a reverse property
*
* This will return all nodes that link to this Node instance via the
* specified property.
*
* @param string $property The name of the reverse property.
*
* @return null|NodeInterface|NodeInterface[] Returns the node(s) pointing
* to this instance via the specified
* property or null if no such node exists.
*/
public function getReverseProperty($property);
/**
* Compares this node object to the specified value.
*
* @param mixed $other The value this instance should be compared to.
*
* @return bool Returns true if the passed value is the same as this
* instance; false otherwise.
*/
public function equals(NodeInterface $other);
}

2973
vendor/ml/json-ld/Processor.php vendored Normal file

File diff suppressed because it is too large Load Diff

152
vendor/ml/json-ld/Quad.php vendored Normal file
View File

@@ -0,0 +1,152 @@
<?php
/*
* (c) Markus Lanthaler <mail@markus-lanthaler.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace ML\JsonLD;
use ML\IRI\IRI;
/**
* A quad
*
* @author Markus Lanthaler <mail@markus-lanthaler.com>
*/
class Quad
{
/**
* The subject
*
* @var IRI
*/
private $subject;
/**
* The property or predicate
*
* @var IRI
*/
private $property;
/**
* The object
*
* @var Value|IRI
*/
private $object;
/**
* The graph
*
* @var IRI
*/
private $graph;
/**
* Constructor
*
* @param IRI $subject The subject.
* @param IRI $property The property.
* @param Value|IRI $object The object.
* @param null|IRI $graph The graph.
*
* @throws InvalidArgumentException If the object parameter has a wrong type
*/
public function __construct(IRI $subject, IRI $property, $object, IRI $graph = null)
{
$this->subject = $subject;
$this->property = $property;
$this->setObject($object); // use setter which checks the type
$this->graph = $graph;
}
/**
* Set the subject
*
* @param IRI $subject The subject
*/
public function setSubject(IRI $subject)
{
$this->subject = $subject;
}
/**
* Get the subject
*
* @return IRI The subject
*/
public function getSubject()
{
return $this->subject;
}
/**
* Set the property
*
* @param IRI $property The property
*/
public function setProperty(IRI $property)
{
$this->property = $property;
}
/**
* Get the property
*
* @return IRI The property
*/
public function getProperty()
{
return $this->property;
}
/**
* Set the object
*
* @param IRI|Value $object The object
*
* @throws InvalidArgumentException If object is of wrong type.
*/
public function setObject($object)
{
if (!($object instanceof IRI) && !($object instanceof Value)) {
throw new \InvalidArgumentException('Object must be an IRI or Value object');
}
$this->object = $object;
}
/**
* Get the object
*
* @return IRI|Value The object
*/
public function getObject()
{
return $this->object;
}
/**
* Set the graph
*
* @param null|IRI $graph The graph
*/
public function setGraph(IRI $graph = null)
{
$this->graph = $graph;
}
/**
* Get the graph
*
* @return IRI The graph
*/
public function getGraph()
{
return $this->graph;
}
}

View File

@@ -0,0 +1,27 @@
<?php
/*
* (c) Markus Lanthaler <mail@markus-lanthaler.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace ML\JsonLD;
/**
* Quad parser interface
*
* @author Markus Lanthaler <mail@markus-lanthaler.com>
*/
interface QuadParserInterface
{
/**
* Parses quads
*
* @param string $input The serialized quads to parse.
*
* @return Quad[] An array of extracted quads.
*/
public function parse($input);
}

View File

@@ -0,0 +1,27 @@
<?php
/*
* (c) Markus Lanthaler <mail@markus-lanthaler.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace ML\JsonLD;
/**
* Quad serializer interface
*
* @author Markus Lanthaler <mail@markus-lanthaler.com>
*/
interface QuadSerializerInterface
{
/**
* Serializes quads to a string.
*
* @param Quad[] $quads Array of quads to be serialized.
*
* @return string The serialized quads.
*/
public function serialize(array $quads);
}

104
vendor/ml/json-ld/README.md vendored Normal file
View File

@@ -0,0 +1,104 @@
JsonLD [![Continuous integration](https://github.com/lanthaler/JsonLD/actions/workflows/ci.yaml/badge.svg)](https://github.com/lanthaler/JsonLD/actions/workflows/ci.yaml)
==============
JsonLD is a fully conforming [JSON-LD](http://www.w3.org/TR/json-ld/)
processor written in PHP. It is extensively tested and passes the
[official JSON-LD test suite](https://github.com/json-ld/tests).
There's an [online playground](http://www.markus-lanthaler.com/jsonld/playground/)
where you can evaluate the processor's basic functionality.
Additionally to the features defined by the [JSON-LD API specification](http://www.w3.org/TR/json-ld-api/),
JsonLD supports [framing](http://json-ld.org/spec/latest/json-ld-framing/)
(including [value matching](https://github.com/json-ld/json-ld.org/issues/110),
[deep-filtering](https://github.com/json-ld/json-ld.org/issues/110),
[aggressive re-embedding](https://github.com/json-ld/json-ld.org/issues/119), and
[named graphs](https://github.com/json-ld/json-ld.org/issues/118)) and an experimental
[object-oriented interface for JSON-LD documents](https://github.com/lanthaler/JsonLD/issues/15).
Installation
------------
The easiest way to install `JsonLD` is by requiring it with [Composer](https://getcomposer.org/).
```
composer require ml/json-ld
```
... and including Composer's autoloader to your project
```php
require('vendor/autoload.php');
```
Of course, you can also download JsonLD as
[ZIP archive](https://github.com/lanthaler/JsonLD/releases) from Github.
JsonLD requires PHP 5.3 or later.
Usage
------------
The library supports the official [JSON-LD API](http://www.w3.org/TR/json-ld-api/) as
well as a object-oriented interface for JSON-LD documents (not fully implemented yet,
see [issue #15](https://github.com/lanthaler/JsonLD/issues/15) for details).
All classes are extensively documented. Please have a look at the source code.
```php
// Official JSON-LD API
$expanded = JsonLD::expand('document.jsonld');
$compacted = JsonLD::compact('document.jsonld', 'context.jsonld');
$framed = JsonLD::frame('document.jsonld', 'frame.jsonld');
$flattened = JsonLD::flatten('document.jsonld');
$quads = JsonLD::toRdf('document.jsonld');
// Output the expanded document (pretty print)
print JsonLD::toString($expanded, true);
// Serialize the quads as N-Quads
$nquads = new NQuads();
$serialized = $nquads->serialize($quads);
print $serialized;
// And parse them again to a JSON-LD document
$quads = $nquads->parse($serialized);
$document = JsonLD::fromRdf($quads);
print JsonLD::toString($document, true);
// Node-centric API
$doc = JsonLD::getDocument('document.jsonld');
// get the default graph
$graph = $doc->getGraph();
// get all nodes in the graph
$nodes = $graph->getNodes();
// retrieve a node by ID
$node = $graph->getNode('http://example.com/node1');
// get a property
$node->getProperty('http://example.com/vocab/name');
// add a new blank node to the graph
$newNode = $graph->createNode();
// link the new blank node to the existing node
$node->addPropertyValue('http://example.com/vocab/link', $newNode);
// even reverse properties are supported; this returns $newNode
$node->getReverseProperty('http://example.com/vocab/link');
// serialize the graph and convert it to a string
$serialized = JsonLD::toString($graph->toJsonLd());
```
Commercial Support
------------
Commercial support is available on request.

28
vendor/ml/json-ld/RdfConstants.php vendored Normal file
View File

@@ -0,0 +1,28 @@
<?php
/*
* (c) Markus Lanthaler <mail@markus-lanthaler.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace ML\JsonLD;
/**
* Some RDF constants.
*
* @author Markus Lanthaler <mail@markus-lanthaler.com>
*/
abstract class RdfConstants
{
const RDF_TYPE = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#type';
const RDF_LIST = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#List';
const RDF_FIRST = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#first';
const RDF_REST = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#rest';
const RDF_NIL = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#nil';
const XSD_INTEGER = 'http://www.w3.org/2001/XMLSchema#integer';
const XSD_DOUBLE = 'http://www.w3.org/2001/XMLSchema#double';
const XSD_BOOLEAN = 'http://www.w3.org/2001/XMLSchema#boolean';
const XSD_STRING = 'http://www.w3.org/2001/XMLSchema#string';
}

57
vendor/ml/json-ld/RemoteDocument.php vendored Normal file
View File

@@ -0,0 +1,57 @@
<?php
/*
* (c) Markus Lanthaler <mail@markus-lanthaler.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace ML\JsonLD;
/**
* RemoteDocument
*
* @author Markus Lanthaler <mail@markus-lanthaler.com>
*/
class RemoteDocument
{
/**
* @var string The URL of the loaded document.
*/
public $documentUrl;
/**
* @var string The document's media type
*/
public $mediaType;
/**
* @var mixed The retrieved document. This can either be the raw payload
* or the already parsed document.
*/
public $document;
/**
* @var string|null The value of the context Link header if available;
* otherwise null.
*/
public $contextUrl;
/**
* Constructor
*
* @param null|string $documentUrl The final URL of the loaded document.
* @param mixed $document The retrieved document (parsed or raw).
* @param null|string $mediaType The document's media type.
* @param null|string $contextUrl The value of the context Link header
* if available; otherwise null.
*/
public function __construct($documentUrl = null, $document = null, $mediaType = null, $contextUrl = null)
{
$this->documentUrl = $documentUrl;
$this->document = $document;
$this->mediaType = $mediaType;
$this->contextUrl = $contextUrl;
}
}

100
vendor/ml/json-ld/Test/DocumentTest.php vendored Normal file
View File

@@ -0,0 +1,100 @@
<?php
/*
* (c) Markus Lanthaler <mail@markus-lanthaler.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace ML\JsonLD\Test;
use ML\JsonLD\JsonLD;
use ML\JsonLD\Document;
/**
* Test the parsing of a JSON-LD document into a Document.
*
* @author Markus Lanthaler <mail@markus-lanthaler.com>
*/
class DocumentTest extends \PHPUnit_Framework_TestCase
{
/**
* The document instance being used throughout the tests.
*
* @var Document
*/
protected $document;
/**
* Create the document to test.
*/
protected function setUp()
{
$this->document = JsonLD::getDocument(
dirname(__FILE__) . DIRECTORY_SEPARATOR . 'Fixtures' . DIRECTORY_SEPARATOR . 'dataset.jsonld',
array('base' => 'http://example.com/dataset.jsonld')
);
}
/**
* Tests whether all nodes are returned and blank nodes are renamed accordingly.
*/
public function testGetIri()
{
$this->assertEquals(
'http://example.com/dataset.jsonld',
$this->document->getIri()
);
}
/**
* Tests whether all nodes are interlinked correctly.
*/
public function testGetGraphNames()
{
// The blank node graph name _:_:graphBn gets relabeled to _:b0 during node map generation
$this->assertEquals(
array('_:b0', 'http://example.com/named-graph'),
$this->document->getGraphNames()
);
}
/**
* Tests whether all nodes also have the correct reverse links.
*/
public function testContainsGraph()
{
$this->assertTrue(
$this->document->containsGraph('/named-graph'),
'Relative IRI'
);
$this->assertTrue(
$this->document->containsGraph('http://example.com/named-graph'),
'Absolute IRI'
);
$this->assertTrue(
$this->document->containsGraph('_:b0'),
'Blank node identifier'
);
$this->assertFalse(
$this->document->containsGraph('http://example.org/not-here'),
'Non-existent graph'
);
}
/**
* Tests isBlankNode()
*/
public function testRemoveGraph()
{
$this->document->removeGraph('/named-graph');
$this->assertFalse(
$this->document->containsGraph('/named-graph'),
'Is the removed graph still there?'
);
}
}

View File

@@ -0,0 +1,273 @@
<?php
/*
* (c) Markus Lanthaler <mail@markus-lanthaler.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace ML\JsonLD\Test;
/**
* EarlReportGenerator
*
* A test listener to create an EARL report. It can be configured uses
* the following configuration
*
* <listeners>
* <listener class="\ML\JsonLD\Test\EarlReportGenerator">
* <arguments>
* <array>
* <element key="target">
* <string>...</string>
* </element>
* <element key="project-name">
* <string>...</string>
* </element>
* <element key="project-url">
* <string>...</string>
* </element>
* <element key="project-homepage">
* <string>...</string>
* </element>
* <element key="license-url">
* <string>...</string>
* </element>
* <element key="project-description">
* <string>...</string>
* </element>
* <element key="programming-language">
* <string>...</string>
* </element>
* <element key="developer-name">
* <string>...</string>
* </element>
* <element key="developer-url">
* <string>...</string>
* </element>
* <element key="developer-homepage">
* <string>...</string>
* </element>
* </array>
* </arguments>
* </listener>
* </listeners>
*
* @author Markus Lanthaler <mail@markus-lanthaler.com>
*/
class EarlReportGenerator extends \PHPUnit_Util_Printer implements \PHPUnit_Framework_TestListener
{
/**
* @var string
*/
protected $testTypeOfInterest = 'ML\\JsonLD\\Test\\W3CTestSuiteTest';
/**
* @var array Lookup table for EARL statuses
*/
protected $earlStatuses;
/**
* @var array Options
*/
protected $options;
/**
* @var array Collected EARL assertions
*/
protected $assertions;
/**
* Constructor
*
* @param array $options Configuration options
*/
public function __construct(array $options = array())
{
$reqOptions = array(
'target',
'project-name',
'project-url',
'project-homepage',
'license-url',
'project-description',
'programming-language',
'developer-name',
'developer-url',
'developer-homepage'
);
foreach ($reqOptions as $option) {
if (false === isset($options[$option])) {
throw new \InvalidArgumentException(
sprintf('The "%s" option is not set', $option)
);
}
}
$this->options = $options;
$this->earlStatuses = array(
\PHPUnit_Runner_BaseTestRunner::STATUS_PASSED => 'earl:passed',
\PHPUnit_Runner_BaseTestRunner::STATUS_SKIPPED => 'earl:untested',
\PHPUnit_Runner_BaseTestRunner::STATUS_INCOMPLETE => 'earl:cantTell',
\PHPUnit_Runner_BaseTestRunner::STATUS_FAILURE => 'earl:failed',
\PHPUnit_Runner_BaseTestRunner::STATUS_ERROR => 'earl:failed'
);
$this->assertions = array();
parent::__construct($options['target']);
}
/**
* A test ended.
*
* @param \PHPUnit_Framework_Test $test
* @param float $time
*/
public function endTest(\PHPUnit_Framework_Test $test, $time)
{
if (false === ($test instanceof $this->testTypeOfInterest)) {
return;
}
$assertion = array(
'@type' => 'earl:Assertion',
'earl:assertedBy' => $this->options['developer-url'],
'earl:mode' => 'earl:automatic',
'earl:test' => $test->getTestId(),
'earl:result' => array(
'@type' => 'earl:TestResult',
'earl:outcome' => $this->earlStatuses[$test->getStatus()],
'dc:date' => date('c')
)
);
$this->assertions[] = $assertion;
}
/**
* @inheritdoc
*/
public function flush()
{
if (0 === $this->assertions) {
return;
}
$report = array(
'@context' => array(
'doap' => 'http://usefulinc.com/ns/doap#',
'foaf' => 'http://xmlns.com/foaf/0.1/',
'dc' => 'http://purl.org/dc/terms/',
'earl' => 'http://www.w3.org/ns/earl#',
'xsd' => 'http://www.w3.org/2001/XMLSchema#',
'doap:homepage' => array('@type' => '@id'),
'doap:license' => array('@type' => '@id'),
'dc:creator' => array('@type' => '@id'),
'foaf:homepage' => array('@type' => '@id'),
'subjectOf' => array('@reverse' => 'earl:subject'),
'earl:assertedBy' => array('@type' => '@id'),
'earl:mode' => array('@type' => '@id'),
'earl:test' => array('@type' => '@id'),
'earl:outcome' => array('@type' => '@id'),
'dc:date' => array('@type' => 'xsd:date')
),
'@id' => $this->options['project-url'],
'@type' => array('doap:Project', 'earl:TestSubject', 'earl:Software'),
'doap:name' => $this->options['project-name'],
'dc:title' => $this->options['project-name'],
'doap:homepage' => $this->options['project-homepage'],
'doap:license' => $this->options['license-url'],
'doap:description' => $this->options['project-description'],
'doap:programming-language' => $this->options['programming-language'],
'doap:developer' => array(
'@id' => $this->options['developer-url'],
'@type' => array('foaf:Person', 'earl:Assertor'),
'foaf:name' => $this->options['developer-name'],
'foaf:homepage' => $this->options['developer-homepage']
),
'dc:creator' => $this->options['developer-url'],
'dc:date' => array(
'@value' => date('Y-m-d'),
'@type' => 'xsd:date'
),
'subjectOf' => $this->assertions
);
$options = 0;
if (PHP_VERSION_ID >= 50400) {
$options |= JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT;
$report = json_encode($report, $options);
} else {
$report = json_encode($report);
$report = str_replace('\\/', '/', $report); // unescape slahes
// unescape unicode
$report = preg_replace_callback(
'/\\\\u([a-f0-9]{4})/',
function ($match) {
return iconv('UCS-4LE', 'UTF-8', pack('V', hexdec($match[1])));
},
$report
);
}
$this->write($report);
parent::flush();
}
/**
* @inheritdoc
*/
public function startTestSuite(\PHPUnit_Framework_TestSuite $suite)
{
}
/**
* @inheritdoc
*/
public function endTestSuite(\PHPUnit_Framework_TestSuite $suite)
{
}
/**
* @inheritdoc
*/
public function addError(\PHPUnit_Framework_Test $test, \Exception $e, $time)
{
}
/**
* @inheritdoc
*/
public function addFailure(\PHPUnit_Framework_Test $test, \PHPUnit_Framework_AssertionFailedError $e, $time)
{
}
/**
* @inheritdoc
*/
public function addIncompleteTest(\PHPUnit_Framework_Test $test, \Exception $e, $time)
{
}
/**
* @inheritdoc
*/
public function addSkippedTest(\PHPUnit_Framework_Test $test, \Exception $e, $time)
{
}
/**
* @inheritdoc
*/
public function startTest(\PHPUnit_Framework_Test $test)
{
}
}

View File

@@ -0,0 +1,99 @@
<?php
/*
* (c) Markus Lanthaler <mail@markus-lanthaler.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace ML\JsonLD\Test;
use ML\IRI\IRI;
use ML\JsonLD\FileGetContentsLoader;
/**
* Test the parsing of a JSON-LD document into a Document.
*/
class FileGetContentsLoaderTest extends \PHPUnit_Framework_TestCase
{
protected $iri;
protected $loader;
public function setUp()
{
parent::setUp();
$this->iri = new IRI('https://www.example.com');
$this->loader = new FileGetContentsLoader;
}
public function tearDown()
{
unset($iri);
unset($this->loader);
parent::tearDown();
}
public function testParseLinkHeadersExactsValues()
{
$headers = array(
'<https://www.example.com>; param1=foo; param2="bar";',
);
$parsed = $this->loader->parseLinkHeaders($headers, $this->iri);
$this->assertEquals('https://www.example.com', $parsed[0]['uri']);
$this->assertEquals('foo', $parsed[0]['param1']);
$this->assertEquals('bar', $parsed[0]['param2']);
}
public function testParseLinkHeadersTrimsValues()
{
$headers = array(
'< https://www.example.com >; param1= foo ; param2=" bar ";',
);
$parsed = $this->loader->parseLinkHeaders($headers, $this->iri);
$this->assertEquals('https://www.example.com', $parsed[0]['uri']);
$this->assertEquals('foo', $parsed[0]['param1']);
$this->assertEquals('bar', $parsed[0]['param2']);
}
public function testParseLinkHeadersWithMultipleHeaders()
{
$headers = array(
'<https://www.example.com>; param1=foo; param2=bar;',
'<https://www.example.org>; param1=fizz; param2=buzz;',
);
$parsed = $this->loader->parseLinkHeaders($headers, $this->iri);
$this->assertCount(2, $parsed);
}
public function testParseLinkHeadersWithMultipleLinks()
{
$headers = array(
'<https://www.example.com>; param1=foo; param2=bar;, '
. '<https://www.example.org>; param1=fizz; param2=buzz;'
);
$parsed = $this->loader->parseLinkHeaders($headers, $this->iri);
$this->assertCount(2, $parsed);
$this->assertEquals('https://www.example.com', $parsed[0]['uri']);
$this->assertEquals('https://www.example.org', $parsed[1]['uri']);
}
public function testParseLinkHeadersConvertsRelativeLinksToAbsolute()
{
$headers = array('</foo/bar>;');
$parsed = $this->loader->parseLinkHeaders($headers, $this->iri);
$this->assertEquals('https://www.example.com/foo/bar', $parsed[0]['uri']);
}
}

View File

@@ -0,0 +1,36 @@
{
"@context": {
"@vocab": "http://example.com/vocab#",
"references": { "@type": "@id" }
},
"@graph": [
{
"@id": "/node1",
"references": [ "_:graphBn", "/named-graph" ]
},
{
"@id": "_:graphBn",
"@graph": [
{
"@id": "_:graphBn/node1",
"name": "_:graphBn/node1",
"references": [ "_:bnode", "/node1", "/named-graph/node1" ]
}
]
},
{
"@id": "/named-graph",
"@graph": [
{
"@id": "/named-graph/node1",
"name": "/named-graph/node1",
"references": [ "_:bnode", "/node1", "_:graphBn/node1" ]
}
]
},
{
"@id": "_:bnode",
"name": "_:bnode"
}
]
}

View File

@@ -0,0 +1,24 @@
{
"@context": {
"t1": "http://example.com/t1",
"t2": "http://example.com/t2",
"term1": "http://example.com/term1",
"term2": "http://example.com/term2",
"term3": "http://example.com/term3",
"term4": "http://example.com/term4",
"term5": "http://example.com/term5"
},
"@id": "http://example.com/id1",
"@type": "t1",
"term1": "v1",
"term2": { "@value": "v2", "@type": "t2" },
"term3": { "@value": "v3", "@language": "en" },
"term4": 4,
"term5": [ 50, 51 ],
"http://example.com/term6": [
{ "@value": "1", "@type": "t1" },
{ "@value": "2", "@type": "t2" },
{ "@value": "3", "@language": "en" },
{ "@value": "4", "@language": "de" }
]
}

View File

@@ -0,0 +1,11 @@
{
"@context": {
"t1": "http://example.com/t1",
"t2": "http://example.com/t2",
"term1": "http://example.com/term1",
"term2": "http://example.com/term2",
"term3": "http://example.com/term3",
"term4": "http://example.com/term4",
"term5": "http://example.com/term5"
}
}

View File

@@ -0,0 +1,20 @@
[
{
"@id": "http://example.com/id1",
"@type": [ "http://example.com/t1" ],
"http://example.com/term1": [ {"@value": "v1"} ],
"http://example.com/term2": [ {"@value": "v2", "@type": "http://example.com/t2"} ],
"http://example.com/term3": [ {"@value": "v3", "@language": "en"} ],
"http://example.com/term4": [ {"@value": 4} ],
"http://example.com/term5": [
{ "@value": 50 },
{ "@value": 51 }
],
"http://example.com/term6": [
{ "@value": "1", "@type": "http://example.com/t1" },
{ "@value": "2", "@type": "http://example.com/t2" },
{ "@value": "3", "@language": "en" },
{ "@value": "4", "@language": "de" }
]
}
]

View File

@@ -0,0 +1,34 @@
{
"@context": {
"t1": "http://example.com/t1",
"t2": "http://example.com/t2",
"term1": "http://example.com/term1",
"term2": "http://example.com/term2",
"term3": "http://example.com/term3",
"term4": "http://example.com/term4",
"term5": "http://example.com/term5"
},
"@graph": [
{
"@id": "http://example.com/id1",
"@type": "t1",
"term1": "v1",
"term2": {
"@type": "t2",
"@value": "v2"
},
"term3": {
"@language": "en",
"@value": "v3"
},
"term4": 4,
"term5": [ 50, 51 ],
"http://example.com/term6": [
{ "@value": "1", "@type": "t1" },
{ "@value": "2", "@type": "t2" },
{ "@value": "3", "@language": "en" },
{ "@value": "4", "@language": "de" }
]
}
]
}

View File

@@ -0,0 +1,22 @@
{
"@context": {
"t1": "http://example.com/t1",
"t2": "http://example.com/t2",
"term1": "http://example.com/term1",
"term3": "http://example.com/term3",
"term5": "http://example.com/term5"
},
"@id": "http://example.com/id1",
"@type": "t1",
"term1": "v1",
"http://example.com/term2": { "@value": "v2", "@type": "t2" },
"term3": { "@value": "v3", "@language": "en" },
"http://example.com/term4": 4,
"term5": [ 50, 51 ],
"http://example.com/term6": [
{ "@value": "1", "@type": "t1" },
{ "@value": "2", "@type": "t2" },
{ "@value": "3", "@language": "en" },
{ "@value": "4", "@language": "de" }
]
}

View File

@@ -0,0 +1,23 @@
[
{
"@id": "http://example.com/id1",
"@type": [ "http://example.com/t1" ],
"http://example.com/term1": [ {"@value": "v1"} ],
"http://example.com/term2": [ {"@value": "v2", "@type": "http://example.com/t2"} ],
"http://example.com/term3": [ {"@value": "v3", "@language": "en"} ],
"http://example.com/term4": [ {"@value": 4} ],
"http://example.com/term5": [
{"@value": 50 },
{"@value": 51 }
],
"http://example.com/term6": [
{ "@value": "1", "@type": "http://example.com/t1" },
{ "@value": "2", "@type": "http://example.com/t2" },
{ "@value": "3", "@language": "en" },
{ "@value": "4", "@language": "de" }
]
},
{
"@id": "http://example.com/t1"
}
]

915
vendor/ml/json-ld/Test/GraphTest.php vendored Normal file
View File

@@ -0,0 +1,915 @@
<?php
/*
* (c) Markus Lanthaler <mail@markus-lanthaler.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace ML\JsonLD\Test;
use ML\JsonLD\Document;
use ML\JsonLD\FileGetContentsLoader;
use ML\JsonLD\Graph;
use ML\JsonLD\GraphInterface;
use ML\JsonLD\Node;
use ML\JsonLD\LanguageTaggedString;
use ML\JsonLD\TypedValue;
use ML\JsonLD\RdfConstants;
/**
* Test the parsing of a JSON-LD document into a Graph.
*
* @author Markus Lanthaler <mail@markus-lanthaler.com>
*/
class GraphTest extends \PHPUnit_Framework_TestCase
{
/**
* The graph instance being used throughout the tests.
*
* @var GraphInterface
*/
protected $graph;
/**
* The document loader used to parse expected values.
*/
protected $documentLoader;
/**
* Create the graph to test.
*/
protected function setUp()
{
$json = <<<JSON_LD_DOCUMENT
{
"@context": {
"ex": "http://vocab.com/",
"ex:lang": { "@language": "en" },
"ex:typed": { "@type": "ex:type/datatype" },
"Node": "ex:type/node"
},
"@graph": [
{
"@id": "1",
"@type": "ex:type/node",
"ex:name": "1",
"ex:link": { "@id": "./2" },
"ex:contains": { "ex:nested": "1.1" }
},
{
"@id": "/node/2",
"ex:name": "2",
"@type": "ex:type/nodeWithAliases",
"ex:lang": "language-tagged string",
"ex:typed": "typed value",
"ex:link": { "@id": "/node/3" },
"ex:contains": [
{ "ex:nested": "2.1" },
{ "ex:nested": "2.2" }
],
"ex:aliases": [ "node2", 2 ]
},
{
"@id": "http://example.com/node/3",
"ex:name": "3",
"@type": "Node",
"ex:link": { "@id": "http://example.com/node/1" },
"ex:contains": {
"@id": "_:someBlankNode",
"ex:nested": "3.1"
},
"ex:lang": [
"language-tagged string: en",
{ "@value": "language-tagged string: de", "@language": "de" },
{ "@value": "language-tagged string: en", "@language": "en" }
],
"ex:typed": [
"typed value",
{ "@value": "typed value", "@language": "ex:/type/otherDataType" },
{ "@value": "typed value", "@language": "ex:/type/datatype" }
]
}
]
}
JSON_LD_DOCUMENT;
$doc = Document::load($json, array('base' => 'http://example.com/node/index.jsonld'));
$this->graph = $doc->getGraph();
$this->documentLoader = new FileGetContentsLoader();
}
/**
* Tests whether all nodes are returned and blank nodes are renamed accordingly.
*/
public function testGetNodes()
{
$nodeIds = array(
'http://example.com/node/1',
'http://example.com/node/2',
'http://example.com/node/3',
'_:b0',
'_:b1',
'_:b2',
'_:b3',
'http://vocab.com/type/node',
'http://vocab.com/type/nodeWithAliases'
);
$nodes = $this->graph->getNodes();
$this->assertCount(count($nodeIds), $nodes);
foreach ($nodes as $node) {
// Is the node's ID valid?
$this->assertContains($node->getId(), $nodeIds, 'Found unexpected node ID: ' . $node->getId());
// Is the node of the right type?
$this->assertInstanceOf('ML\JsonLD\Node', $node);
// Does the graph return the same instance?
$n = $this->graph->getNode($node->getId());
$this->assertSame($node, $n, 'same instance');
$this->assertTrue($node->equals($n), 'equals');
$this->assertSame($this->graph, $n->getGraph(), 'linked to graph');
}
}
/**
* Tests whether all nodes are interlinked correctly.
*/
public function testNodeRelationships()
{
$node1 = $this->graph->getNode('http://example.com/node/1');
$node2 = $this->graph->getNode('http://example.com/node/2');
$node3 = $this->graph->getNode('http://example.com/node/3');
$node1_1 = $this->graph->getNode('_:b0');
$node2_1 = $this->graph->getNode('_:b1');
$node2_2 = $this->graph->getNode('_:b2');
$node3_1 = $this->graph->getNode('_:b3');
$nodeType = $this->graph->getNode('http://vocab.com/type/node');
$nodeWithAliasesType = $this->graph->getNode('http://vocab.com/type/nodeWithAliases');
$this->assertSame($node2, $node1->getProperty('http://vocab.com/link'), 'n1 -link-> n2');
$this->assertSame($node1_1, $node1->getProperty('http://vocab.com/contains'), 'n1 -contains-> n1.1');
$this->assertSame($nodeType, $node1->getType(), 'n1 type');
$this->assertSame($node3, $node2->getProperty('http://vocab.com/link'), 'n2 -link-> n3');
$values = $node2->getProperty('http://vocab.com/contains');
$this->assertCount(2, $values, 'n2 -contains-> 2 nodes');
$this->assertSame($node2_1, $values[0], 'n2 -contains-> n2.1');
$this->assertSame($node2_2, $values[1], 'n2 -contains-> n2.1');
$this->assertSame($nodeWithAliasesType, $node2->getType(), 'n2 type');
$this->assertSame($node1, $node3->getProperty('http://vocab.com/link'), 'n3 -link-> n1');
$this->assertSame($node3_1, $node3->getProperty('http://vocab.com/contains'), 'n3 -contains-> n3.1');
$this->assertSame($nodeType, $node3->getType(), 'n3 type');
}
/**
* Tests whether all nodes also have the correct reverse links.
*/
public function testNodeReverseRelationships()
{
$node1 = $this->graph->getNode('http://example.com/node/1');
$node2 = $this->graph->getNode('http://example.com/node/2');
$node3 = $this->graph->getNode('http://example.com/node/3');
$node1_1 = $this->graph->getNode('_:b0');
$node2_1 = $this->graph->getNode('_:b1');
$node2_2 = $this->graph->getNode('_:b2');
$node3_1 = $this->graph->getNode('_:b3');
$nodeType = $this->graph->getNode('http://vocab.com/type/node');
$nodeWithAliasesType = $this->graph->getNode('http://vocab.com/type/nodeWithAliases');
$this->assertSame($node1, $node2->getReverseProperty('http://vocab.com/link'), 'n2 <-link- n1');
$this->assertSame($node1, $node1_1->getReverseProperty('http://vocab.com/contains'), 'n1.1 <-contains- n1');
$this->assertSame($node2, $node3->getReverseProperty('http://vocab.com/link'), 'n3 <-link- n2');
$this->assertSame($node2, $node2_1->getReverseProperty('http://vocab.com/contains'), 'n2.1 <-contains- n2');
$this->assertSame($node2, $node2_2->getReverseProperty('http://vocab.com/contains'), 'n2.1 <-contains- n2');
$this->assertSame($node3, $node1->getReverseProperty('http://vocab.com/link'), 'n1 <-link- n3');
$this->assertSame($node3, $node3_1->getReverseProperty('http://vocab.com/contains'), 'n3.1 <-contains- n3');
$this->assertSame(array($node1, $node3), $nodeType->getReverseProperty(Node::TYPE), 'n1+n3 <-type- nodeType');
$this->assertSame(array($node2), $nodeWithAliasesType->getNodesWithThisType(), 'n2 <-type- nodeWithAliases');
}
/**
* Tests isBlankNode()
*/
public function testNodeIsBlankNode()
{
$this->assertFalse($this->graph->getNode('http://example.com/node/1')->isBlankNode(), 'n1');
$this->assertFalse($this->graph->getNode('http://example.com/node/2')->isBlankNode(), 'n2');
$this->assertFalse($this->graph->getNode('http://example.com/node/3')->isBlankNode(), 'n3');
$this->assertTrue($this->graph->getNode('_:b0')->isBlankNode(), '_:b0');
$this->assertTrue($this->graph->getNode('_:b1')->isBlankNode(), '_:b1');
$this->assertTrue($this->graph->getNode('_:b2')->isBlankNode(), '_:b2');
$this->assertTrue($this->graph->getNode('_:b3')->isBlankNode(), '_:b3');
$node = $this->graph->createNode();
$this->assertTrue($node->isBlankNode(), 'new node without ID');
$node = $this->graph->createNode('_:fljdf');
$this->assertTrue($node->isBlankNode(), 'new node blank node ID');
$node = $this->graph->createNode('http://www.example.com/node/new');
$this->assertFalse($node->isBlankNode(), 'new node with ID');
}
/**
* Tests if reverse node relationships are updated when a property is updated.
*/
public function testNodeReverseRelationshipsUpdated()
{
$node1 = $this->graph->getNode('http://example.com/node/1');
$node1_1 = $this->graph->getNode('_:b0');
$node2 = $this->graph->getNode('http://example.com/node/2');
$node3 = $this->graph->getNode('http://example.com/node/3');
$nodeType = $this->graph->getNode('http://vocab.com/type/node');
$nodeWithAliasesType = $this->graph->getNode('http://vocab.com/type/nodeWithAliases');
$revProperties = $node2->getReverseProperties();
$this->assertCount(1, $revProperties, 'Check number of node2\'s reverse properties');
$this->assertSame(
array('http://vocab.com/link' => array($node1)),
$revProperties,
'Check node2\'s reverse properties'
);
$node1->setProperty('http://vocab.com/link', null);
$this->assertNull($node1->getProperty('http://vocab.com/link'), 'n1 -link-> n2 removed');
$node1->removePropertyValue('http://vocab.com/contains', $node1_1);
$this->assertNull($node1->getProperty('http://vocab.com/contains'), 'n1 -contains-> n1.1 removed');
$this->assertNull($node2->getReverseProperty('http://vocab.com/link'), 'n2 <-link- n1 removed');
$this->assertNull($node1_1->getReverseProperty('http://vocab.com/contains'), 'n1.1 <-contains- n1 removed');
$expectedProperties = array(
Node::TYPE => $this->graph->getNode('http://vocab.com/type/node'),
'http://vocab.com/name' => new TypedValue('1', RdfConstants::XSD_STRING)
);
$properties = $node1->getProperties();
$this->assertCount(2, $properties, 'Check number of properties');
$this->assertEquals($expectedProperties, $properties, 'Check properties');
$this->assertSame(array($node1, $node3), $nodeType->getNodesWithThisType(), 'n1+n3 <-type- nodeType');
$this->assertSame($node2, $nodeWithAliasesType->getReverseProperty(Node::TYPE), 'n2 <-type- nodeWithAliases');
$node1->setType(null);
$node2->removeType($nodeWithAliasesType);
$this->assertSame($node3, $nodeType->getReverseProperty(Node::TYPE), 'n3 <-type- nodeType');
$this->assertSame(array(), $nodeWithAliasesType->getNodesWithThisType(), 'nodeWithAliases removed from n2');
}
/**
* Tests the removal of nodes from the graph.
*/
public function testNodeRemoval()
{
// Remove node 1
$node1 = $this->graph->getNode('/node/1');
$node1_1 = $this->graph->getNode('_:b0');
$node2 = $this->graph->getNode('http://example.com/node/2');
$this->assertTrue($this->graph->containsNode('http://example.com/node/1'), 'node 1 in graph?');
$this->assertSame(
array('http://vocab.com/link' => array($node1)),
$node2->getReverseProperties(),
'Check node2\'s reverse properties'
);
$this->assertSame(
array('http://vocab.com/contains' => array($node1)),
$node1_1->getReverseProperties(),
'Check node1.1\'s reverse properties'
);
$node1->removeFromGraph();
$this->assertSame(array(), $node2->getReverseProperties(), 'n2 reverse properties');
$this->assertNull($node2->getReverseProperty('http://vocab.com/link'), 'n2 <-link- n1 removed');
$this->assertSame(array(), $node1_1->getReverseProperties(), 'n1.1 reverse properties');
$this->assertNull($node1_1->getReverseProperty('http://vocab.com/contains'), 'n1.1 <-contains- n1 removed');
$this->assertFalse($this->graph->containsNode('/node/1'), 'node 1 still in graph?');
$this->assertNull($node1->getGraph(), 'node 1\'s graph reset?');
// Remove node 2
$node2 = $this->graph->getNode('http://example.com/node/2');
$node2_1 = $this->graph->getNode('_:b1');
$node2_2 = $this->graph->getNode('_:b2');
$node3 = $this->graph->getNode('/node/3');
$this->assertTrue($this->graph->containsNode('/node/2'), 'node 2 in graph?');
$this->assertSame(
array('http://vocab.com/link' => array($node2)),
$node3->getReverseProperties(),
'Check node3\'s reverse properties'
);
$this->assertSame(
array('http://vocab.com/contains' => array($node2)),
$node2_1->getReverseProperties(),
'Check node2.1\'s reverse properties'
);
$this->assertSame(
array('http://vocab.com/contains' => array($node2)),
$node2_2->getReverseProperties(),
'Check node2.2\'s reverse properties'
);
$this->graph->removeNode($node2);
$this->assertSame(array(), $node3->getReverseProperties(), 'n3 reverse properties');
$this->assertNull($node3->getReverseProperty('http://vocab.com/link'), 'n3 <-link- n2 removed');
$this->assertSame(array(), $node2_1->getReverseProperties(), 'n2.1 reverse properties');
$this->assertNull($node2_1->getReverseProperty('http://vocab.com/contains'), 'n2.1 <-contains- n2 removed');
$this->assertSame(array(), $node2_2->getReverseProperties(), 'n2.2 reverse properties');
$this->assertNull($node2_2->getReverseProperty('http://vocab.com/contains'), 'n2.2 <-contains- n2 removed');
$this->assertFalse($this->graph->containsNode('./2'), 'node 2 still in graph?');
}
/**
* Tests the removal of node types from the graph.
*/
public function testNodeTypeRemoval()
{
// Remove nodeType
$node1 = $this->graph->getNode('http://example.com/node/1');
$node3 = $this->graph->getNode('/node/3');
$nodeType = $this->graph->getNode('http://vocab.com/type/node');
$this->assertTrue($this->graph->containsNode('http://vocab.com/type/node'), 'node type in graph?');
$this->assertSame($nodeType, $node1->getType(), 'n1 type');
$this->assertSame($nodeType, $node3->getType(), 'n3 type');
$this->assertSame(
array(Node::TYPE => array($node1, $node3)),
$nodeType->getReverseProperties(),
'Check node type\'s reverse properties'
);
$this->graph->removeNode($nodeType);
$this->assertSame(array(), $nodeType->getReverseProperties(), 'node type\'s reverse properties');
$this->assertSame(array(), $nodeType->getNodesWithThisType(), 'n1+n3 <-type- node type removed');
$this->assertNull($node1->getType(), 'n1 type removed');
$this->assertNull($node3->getType(), 'n3 type removed');
$this->assertFalse($this->graph->containsNode('http://vocab.com/type/node'), 'node type still in graph?');
}
/**
* Tests if adding a value maintains uniqueness
*/
public function testNodePropertyUniqueness()
{
// Null
$node = $this->graph->getNode('http://example.com/node/1');
$this->assertNull($node->getProperty('http://example.com/node/1'), 'inexistent');
$node->addPropertyValue('http://vocab.com/inexistent', null);
$this->assertNull($node->getProperty('http://example.com/node/1'), 'inexistent + null');
$node->removeProperty('http://vocab.com/inexistent');
$node->removePropertyValue('http://vocab.com/inexistent', null);
$this->assertNull($node->getProperty('http://example.com/node/1'), 'inexistent removed');
// Scalars
$node = $this->graph->getNode('http://example.com/node/1');
$initialNameValue = $node->getProperty('http://vocab.com/name');
$this->assertEquals(
new TypedValue('1', RdfConstants::XSD_STRING),
$node->getProperty('http://vocab.com/name'),
'name: initial value'
);
$node->addPropertyValue('http://vocab.com/name', '1');
$node->addPropertyValue('http://vocab.com/name', null);
$this->assertSame($initialNameValue, $node->getProperty('http://vocab.com/name'), 'name: still same');
$node->addPropertyValue('http://vocab.com/name', 1);
$this->assertEquals(
array($initialNameValue, new TypedValue('1', RdfConstants::XSD_INTEGER)),
$node->getProperty('http://vocab.com/name'),
'name: new value'
);
$node->removePropertyValue('http://vocab.com/name', 1);
$this->assertSame($initialNameValue, $node->getProperty('http://vocab.com/name'), 'name: removed new value');
// Language-tagged strings
$node = $this->graph->getNode('http://example.com/node/2');
$value = $node->getProperty('http://vocab.com/lang');
$this->assertInstanceOf('ML\JsonLD\LanguageTaggedString', $value, 'lang: initial value type');
$this->assertEquals('language-tagged string', $value->getValue(), 'lang: initial value');
$this->assertEquals('en', $value->getLanguage(), 'lang: initial language');
$sameLangValue = new LanguageTaggedString('language-tagged string', 'en');
$this->assertTrue($value->equals($sameLangValue), 'lang: equals same');
$newLangValue1 = new LanguageTaggedString('language-tagged string', 'de');
$this->assertFalse($value->equals($newLangValue1), 'lang: equals new1');
$newLangValue2 = new LanguageTaggedString('other language-tagged string', 'en');
$this->assertFalse($value->equals($newLangValue2), 'lang: equals new2');
$node->addPropertyValue('http://vocab.com/lang', $sameLangValue);
$this->assertSame($value, $node->getProperty('http://vocab.com/lang'), 'lang: still same');
$node->addPropertyValue('http://vocab.com/lang', $newLangValue1);
$node->addPropertyValue('http://vocab.com/lang', $newLangValue2);
$value = $node->getProperty('http://vocab.com/lang');
$this->assertCount(3, $value, 'lang: count values added');
$this->assertTrue($sameLangValue->equals($value[0]), 'lang: check values 1');
$this->assertTrue($newLangValue1->equals($value[1]), 'lang: check values 2');
$this->assertTrue($newLangValue2->equals($value[2]), 'lang: check values 3');
$node->removePropertyValue('http://vocab.com/lang', $newLangValue1);
$value = $node->getProperty('http://vocab.com/lang');
$this->assertCount(2, $value, 'lang: count value 1 removed again');
$this->assertTrue($sameLangValue->equals($value[0]), 'lang: check values 1 (2)');
$this->assertTrue($newLangValue2->equals($value[1]), 'lang: check values 2 (2)');
// Typed values
$node = $this->graph->getNode('http://example.com/node/2');
$value = $node->getProperty('http://vocab.com/typed');
$this->assertInstanceOf('ML\JsonLD\TypedValue', $value, 'typed: initial value class');
$this->assertEquals('typed value', $value->getValue(), 'typed: initial value');
$this->assertEquals('http://vocab.com/type/datatype', $value->getType(), 'typed: initial value type');
$sameTypedValue = new TypedValue('typed value', 'http://vocab.com/type/datatype');
$this->assertTrue($value->equals($sameTypedValue), 'typed: equals same');
$newTypedValue1 = new TypedValue('typed value', 'http://vocab.com/otherType');
$this->assertFalse($value->equals($newTypedValue1), 'typed: equals new1');
$newTypedValue2 = new TypedValue('other typed value', 'http://vocab.com/type/datatype');
$this->assertFalse($value->equals($newTypedValue2), 'typed: equals new2');
$node->addPropertyValue('http://vocab.com/typed', $sameTypedValue);
$this->assertSame($value, $node->getProperty('http://vocab.com/typed'), 'typed: still same');
$node->addPropertyValue('http://vocab.com/typed', $newTypedValue1);
$node->addPropertyValue('http://vocab.com/typed', $newTypedValue2);
$value = $node->getProperty('http://vocab.com/typed');
$this->assertCount(3, $value, 'typed: count values added');
$this->assertTrue($sameTypedValue->equals($value[0]), 'typed: check values 1');
$this->assertTrue($newTypedValue1->equals($value[1]), 'typed: check values 2');
$this->assertTrue($newTypedValue2->equals($value[2]), 'typed: check values 3');
$node->removePropertyValue('http://vocab.com/typed', $newTypedValue1);
$value = $node->getProperty('http://vocab.com/typed');
$this->assertCount(2, $value, 'typed: count value 1 removed again');
$this->assertTrue($sameTypedValue->equals($value[0]), 'typed: check values 1 (2)');
$this->assertTrue($newTypedValue2->equals($value[1]), 'typed: check values 2 (2)');
// Nodes
$node = $this->graph->getNode('http://example.com/node/3');
$node1 = $this->graph->getNode('http://example.com/node/1');
$value = $node->getProperty('http://vocab.com/link');
$this->assertInstanceOf('ML\JsonLD\Node', $value, 'node: initial value class');
$this->assertSame($node1, $value, 'node: initial node');
$newNode1 = $this->graph->createNode();
$this->assertTrue($this->graph->containsNode($newNode1), 'node: new1 in graph');
$newNode2 = $this->graph->createNode('http://example.com/node/new/2');
$this->assertTrue($this->graph->containsNode($newNode2), 'node: new2 in graph');
$node->addPropertyValue('http://vocab.com/link', $node1);
$this->assertSame($node1, $node->getProperty('http://vocab.com/link'), 'node: still same');
$node->addPropertyValue('http://vocab.com/link', $newNode1);
$node->addPropertyValue('http://vocab.com/link', $newNode2);
$value = $node->getProperty('http://vocab.com/link');
$this->assertCount(3, $value, 'node: count values added');
$this->assertSame($node1, $value[0], 'node: check values 1');
$this->assertSame($newNode1, $value[1], 'node: check values 2');
$this->assertSame($newNode2, $value[2], 'node: check values 3');
$node->removePropertyValue('http://vocab.com/link', $newNode1);
$value = $node->getProperty('http://vocab.com/link');
$this->assertCount(2, $value, 'typed: count new node 1 removed again');
$this->assertTrue($node1->equals($value[0]), 'node: check values 1 (2)');
$this->assertTrue($newNode2->equals($value[1]), 'node: check values 2 (2)');
// Node types
$node1 = $this->graph->getNode('http://example.com/node/1');
$nodeType = $this->graph->getNode('http://vocab.com/type/node');
$nodeWithAliasesType = $this->graph->getNode('http://vocab.com/type/nodeWithAliases');
$this->assertSame($nodeType, $node1->getType(), 'type: n1 initial type');
$newType1 = $this->graph->createNode();
$this->assertTrue($this->graph->containsNode($newNode1), 'type: new1 in graph');
$node1->addType($nodeType);
$this->assertSame($nodeType, $node1->getType(), 'type: n1 type still same');
$node1->addType($nodeWithAliasesType);
$node1->addType($newType1);
$value = $node1->getType();
$this->assertCount(3, $value, 'type: count values added');
$this->assertSame($nodeType, $value[0], 'type: check values 1');
$this->assertSame($nodeWithAliasesType, $value[1], 'type: check values 2');
$this->assertSame($newType1, $value[2], 'type: check values 3');
$node1->removeType($nodeWithAliasesType);
$value = $node1->getType();
$this->assertCount(2, $value, 'typed: count nodeWithAliasesType removed again');
$this->assertTrue($nodeType->equals($value[0]), 'type: check values 1 (2)');
$this->assertTrue($newType1->equals($value[1]), 'type: check values 2 (2)');
}
/**
* Tests whether it is possible to add invalid values
*
* @expectedException InvalidArgumentException
*/
public function testAddInvalidPropertyValue()
{
$graph = new Graph();
$newNode = $graph->createNode();
$node1 = $this->graph->getNode('http://example.com/node/1');
$node1->addPropertyValue('http://vocab.com/link', $newNode);
}
/**
* Tests whether it is possible to set the node's type to an invalid
* value
*
* @expectedException InvalidArgumentException
*/
public function testSetInvalidTypeValue()
{
$node1 = $this->graph->getNode('http://example.com/node/1');
$node1->setType('http://vocab.com/type/aTypeAsString');
}
/**
* Tests whether it is possible to set the node's type to an invalid
* value when an array is used.
*
* @expectedException InvalidArgumentException
*/
public function testSetInvalidTypeArray()
{
$types = array(
$this->graph->getNode('http://vocab.com/type/nodeWithAliases'),
'http://vocab.com/type/aTypeAsString'
);
$node1 = $this->graph->getNode('http://example.com/node/1');
$node1->setType($types);
}
/**
* Tests whether it is possible to add an type which is not part of the
* graph
*
* @expectedException InvalidArgumentException
*/
public function testAddTypeNotInGraph()
{
$graph = new Graph();
$newType = $graph->createNode();
$node1 = $this->graph->getNode('http://example.com/node/1');
$node1->addType($newType);
}
/**
* Tests whether nodes are contained in the graph
*/
public function testContains()
{
$node1 = $this->graph->getNode('http://example.com/node/1');
$nodeb_0 = $this->graph->getNode('_:b0');
$this->assertTrue($this->graph->containsNode($node1), 'node1 obj');
$this->assertTrue($this->graph->containsNode('http://example.com/node/1'), 'node1 IRI');
$this->assertFalse($this->graph->containsNode('http://example.com/node/X'), 'inexistent IRI');
$this->assertTrue($this->graph->containsNode($nodeb_0), '_:b0');
$this->assertFalse($this->graph->containsNode('_:b0'), '_:b0 IRI');
$this->assertFalse($this->graph->containsNode(new TypedValue('val', 'http://example.com/type')), 'typed value');
}
/**
* Tests whether creating an existing node returns the instance of that node
*/
public function testCreateExistingNode()
{
$node1 = $this->graph->getNode('http://example.com/node/1');
$nodeType = $this->graph->getNode('http://vocab.com/type/node');
$this->assertSame($node1, $this->graph->createNode('http://example.com/node/1'));
$this->assertSame($nodeType, $this->graph->createNode('http://vocab.com/type/node'));
}
/**
* Tests the merging of two graphs
*/
public function testMerge()
{
$this->markTestSkipped("Merging graphs doesn't work yet as blank nodes are not relabeled properly");
$json = <<<JSON_LD_DOCUMENT
{
"@context": {
"ex": "http://vocab.com/",
"node": "ex:type/node"
},
"@graph": [
{
"@id": "1",
"@type": "ex:type/node",
"ex:name": "1",
"ex:link": { "@id": "./2" },
"ex:contains": { "ex:nested": "1.1 (graph 2)" }
},
{
"@id": "/node/2",
"ex:name": "and a different name in graph 2",
"ex:link": { "@id": "/node/4" },
"ex:newFromGraph2": "this was added in graph 2"
},
{
"@id": "http://example.com/node/4",
"ex:name": "node 4 from graph 2"
}
]
}
JSON_LD_DOCUMENT;
$graph2 = Document::load($json, array('base' => 'http://example.com/node/index.jsonld'))->getGraph();
// Merge graph2 into graph
$this->graph->merge($graph2);
$nodeIds = array(
'http://example.com/node/1',
'http://example.com/node/2',
'http://example.com/node/3',
'http://example.com/node/4',
'_:b0',
'_:b1',
'_:b2',
'_:b3',
'_:b4',
'http://vocab.com/type/node',
'http://vocab.com/type/nodeWithAliases'
);
$nodes = $this->graph->getNodes();
$this->assertCount(count($nodeIds), $nodes);
foreach ($nodes as $node) {
// Is the node's ID valid?
$this->assertContains($node->getId(), $nodeIds, 'Found unexpected node ID: ' . $node->getId());
// Is the node of the right type?
$this->assertInstanceOf('ML\JsonLD\Node', $node);
// Does the graph return the same instance?
$n = $this->graph->getNode($node->getId());
$this->assertSame($node, $n, 'same instance');
$this->assertTrue($node->equals($n), 'equals');
$this->assertSame($this->graph, $n->getGraph(), 'linked to graph');
// It must not share node objects with graph 2
$this->assertNotSame($node, $graph2->getNode($node->getId()), 'shared instance between graph and graph 2');
}
// Check that the properties have been updated as well
$node1 = $this->graph->getNode('http://example.com/node/1');
$node2 = $this->graph->getNode('http://example.com/node/2');
$node3 = $this->graph->getNode('http://example.com/node/3');
$node4 = $this->graph->getNode('http://example.com/node/4');
$this->assertEquals(
new TypedValue('1', RdfConstants::XSD_STRING),
$node1->getProperty('http://vocab.com/name'),
'n1->name'
);
$this->assertSame($node2, $node1->getProperty('http://vocab.com/link'), 'n1 -link-> n2');
$this->assertCount(2, $node1->getProperty('http://vocab.com/contains'), 'n1 -contains-> 2 blank nodes');
$this->assertEquals(
array(
new TypedValue('2', RdfConstants::XSD_STRING),
new TypedValue('and a different name in graph 2', RdfConstants::XSD_STRING)
),
$node2->getProperty('http://vocab.com/name'),
'n2->name'
);
$this->assertSame(array($node3, $node4), $node2->getProperty('http://vocab.com/link'), 'n2 -link-> n3 & n4');
$this->assertEquals(
new TypedValue('this was added in graph 2', RdfConstants::XSD_STRING),
$node2->getProperty('http://vocab.com/newFromGraph2'),
'n2->newFromGraph2'
);
$this->assertEquals(
new TypedValue('node 4 from graph 2', RdfConstants::XSD_STRING),
$node4->getProperty('http://vocab.com/name'),
'n4->name'
);
// Verify that graph 2 wasn't changed
$nodeIds = array(
'http://example.com/node/1',
'http://example.com/node/2',
'_:b0', // ex:contains: { ex:nested }
'http://example.com/node/4',
'http://vocab.com/type/node'
);
$nodes = $graph2->getNodes();
$this->assertCount(count($nodeIds), $nodes);
foreach ($nodes as $node) {
// Is the node's ID valid?
$this->assertContains($node->getId(), $nodeIds, 'Found unexpected node ID in graph 2: ' . $node->getId());
// Is the node of the right type?
$this->assertInstanceOf('ML\JsonLD\Node', $node);
// Does the graph return the same instance?
$n = $graph2->getNode($node->getId());
$this->assertSame($node, $n, 'same instance (graph 2)');
$this->assertTrue($node->equals($n), 'equals (graph 2)');
$this->assertSame($graph2, $n->getGraph(), 'linked to graph (graph 2)');
}
}
/**
* Tests the serialization of nodes
*/
public function testSerializeNode()
{
$expected = $this->documentLoader->loadDocument(
'{
"@id": "http://example.com/node/1",
"@type": [ "http://vocab.com/type/node" ],
"http://vocab.com/name": [ { "@value": "1" } ],
"http://vocab.com/link": [ { "@id": "http://example.com/node/2" } ],
"http://vocab.com/contains": [ { "@id": "_:b0" } ]
}'
);
$expected = $expected->document;
$node1 = $this->graph->getNode('http://example.com/node/1');
$this->assertEquals($expected, $node1->toJsonLd(), 'Serialize node 1');
}
/**
* Tests the serialization of graphs
*/
public function testSerializeGraph()
{
// This is the expanded and flattened version of the test document
// (the blank node labels have been renamed from _:t... to _:b...)
$expected = $this->documentLoader->loadDocument(
'[{
"@id": "_:b0",
"http://vocab.com/nested": [{
"@value": "1.1"
}]
}, {
"@id": "_:b1",
"http://vocab.com/nested": [{
"@value": "2.1"
}]
}, {
"@id": "_:b2",
"http://vocab.com/nested": [{
"@value": "2.2"
}]
}, {
"@id": "_:b3",
"http://vocab.com/nested": [{
"@value": "3.1"
}]
}, {
"@id": "http://example.com/node/1",
"@type": ["http://vocab.com/type/node"],
"http://vocab.com/contains": [{
"@id": "_:b0"
}],
"http://vocab.com/link": [{
"@id": "http://example.com/node/2"
}],
"http://vocab.com/name": [{
"@value": "1"
}]
}, {
"@id": "http://example.com/node/2",
"@type": ["http://vocab.com/type/nodeWithAliases"],
"http://vocab.com/aliases": [{
"@value": "node2"
}, {
"@value": 2,
"@type": "http://www.w3.org/2001/XMLSchema#integer"
}],
"http://vocab.com/contains": [{
"@id": "_:b1"
}, {
"@id": "_:b2"
}],
"http://vocab.com/lang": [{
"@language": "en",
"@value": "language-tagged string"
}],
"http://vocab.com/link": [{
"@id": "http://example.com/node/3"
}],
"http://vocab.com/name": [{
"@value": "2"
}],
"http://vocab.com/typed": [{
"@type": "http://vocab.com/type/datatype",
"@value": "typed value"
}]
}, {
"@id": "http://example.com/node/3",
"@type": ["http://vocab.com/type/node"],
"http://vocab.com/contains": [{
"@id": "_:b3"
}],
"http://vocab.com/lang": [{
"@language": "en",
"@value": "language-tagged string: en"
}, {
"@language": "de",
"@value": "language-tagged string: de"
}],
"http://vocab.com/link": [{
"@id": "http://example.com/node/1"
}],
"http://vocab.com/name": [{
"@value": "3"
}],
"http://vocab.com/typed": [{
"@type": "http://vocab.com/type/datatype",
"@value": "typed value"
}, {
"@language": "ex:/type/otherDataType",
"@value": "typed value"
}, {
"@language": "ex:/type/datatype",
"@value": "typed value"
}]
}, {
"@id": "http://vocab.com/type/node"
}, {
"@id": "http://vocab.com/type/nodeWithAliases"
}]'
);
$expected = $expected->document;
$this->assertEquals($expected, $this->graph->toJsonLd(false), 'Serialize graph');
}
}

132
vendor/ml/json-ld/Test/JsonLDApiTest.php vendored Normal file
View File

@@ -0,0 +1,132 @@
<?php
/*
* (c) Markus Lanthaler <mail@markus-lanthaler.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace ML\JsonLD\Test;
use ML\JsonLD\JsonLD;
/**
* Tests JsonLD's API
*
* @author Markus Lanthaler <mail@markus-lanthaler.com>
*/
class JsonLDApiTest extends JsonTestCase
{
/**
* Tests the expansion API
*
* @group expansion
*/
public function testExpansion()
{
$path = dirname(__FILE__) . DIRECTORY_SEPARATOR . 'Fixtures' . DIRECTORY_SEPARATOR;
$expected = json_decode(file_get_contents($path . 'sample-expanded.jsonld'));
$input = $path . 'sample-in.jsonld';
$this->assertJsonEquals($expected, JsonLD::expand($input), 'Passing the file path');
$input = file_get_contents($input);
$this->assertJsonEquals($expected, JsonLD::expand($input), 'Passing the raw input (string)');
$input = json_decode($input);
$this->assertJsonEquals($expected, JsonLD::expand($input), 'Passing the parsed object');
}
/**
* Tests the compaction API
*
* @group compaction
*/
public function testCompaction()
{
$path = dirname(__FILE__) . DIRECTORY_SEPARATOR . 'Fixtures' . DIRECTORY_SEPARATOR;
$expected = json_decode(file_get_contents($path . 'sample-compacted.jsonld'));
$input = $path . 'sample-in.jsonld';
$context = $path . 'sample-context.jsonld';
$this->assertJsonEquals($expected, JsonLD::compact($input, $context), 'Passing the file path');
$input = file_get_contents($input);
$context = file_get_contents($context);
$this->assertJsonEquals($expected, JsonLD::compact($input, $context), 'Passing the raw input (string)');
$input = json_decode($input);
$context = json_decode($context);
$this->assertJsonEquals($expected, JsonLD::compact($input, $context), 'Passing the parsed object');
}
/**
* Tests the flattening API
*
* @group flattening
*/
public function testFlatten()
{
$path = dirname(__FILE__) . DIRECTORY_SEPARATOR . 'Fixtures' . DIRECTORY_SEPARATOR;
$expected = json_decode(file_get_contents($path . 'sample-flattened.jsonld'));
$input = $path . 'sample-in.jsonld';
$context = $path . 'sample-context.jsonld';
$this->assertJsonEquals($expected, JsonLD::flatten($input, $context), 'Passing the file path');
$input = file_get_contents($input);
$context = file_get_contents($context);
$this->assertJsonEquals($expected, JsonLD::flatten($input, $context), 'Passing the raw input (string)');
$input = json_decode($input);
$context = json_decode($context);
$this->assertJsonEquals($expected, JsonLD::flatten($input, $context), 'Passing the parsed object');
}
/**
* Tests the framing API
*
* This test intentionally uses the same fixtures as the flattening tests.
*
* @group framing
*/
public function testFrame()
{
$path = dirname(__FILE__) . DIRECTORY_SEPARATOR . 'Fixtures' . DIRECTORY_SEPARATOR;
$expected = json_decode(file_get_contents($path . 'sample-flattened.jsonld'));
$input = $path . 'sample-in.jsonld';
$context = $path . 'sample-context.jsonld';
$this->assertJsonEquals($expected, JsonLD::frame($input, $context), 'Passing the file path');
$input = file_get_contents($input);
$context = file_get_contents($context);
$this->assertJsonEquals($expected, JsonLD::frame($input, $context), 'Passing the raw input (string)');
$input = json_decode($input);
$context = json_decode($context);
$this->assertJsonEquals($expected, JsonLD::frame($input, $context), 'Passing the parsed object');
}
/**
* Tests the document API
*
* This test intentionally uses the same fixtures as the flattening tests.
*/
public function testGetDocument()
{
$path = dirname(__FILE__) . DIRECTORY_SEPARATOR . 'Fixtures' . DIRECTORY_SEPARATOR;
$expected = json_decode(file_get_contents($path . 'sample-serialized-document.jsonld'));
$input = $path . 'sample-in.jsonld';
$this->assertJsonEquals($expected, JsonLD::getDocument($input)->toJsonLd(), 'Passing the file path');
$input = file_get_contents($input);
$this->assertJsonEquals($expected, JsonLD::getDocument($input)->toJsonLd(), 'Passing the raw input (string)');
$input = json_decode($input);
$this->assertJsonEquals($expected, JsonLD::getDocument($input)->toJsonLd(), 'Passing the parsed object');
}
}

64
vendor/ml/json-ld/Test/JsonTestCase.php vendored Normal file
View File

@@ -0,0 +1,64 @@
<?php
/*
* (c) Markus Lanthaler <mail@markus-lanthaler.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace ML\JsonLD\Test;
/**
* A JSON Test Case
*
* This class extends {@link \PHPUnit_Framework_TestCase} with an assertion
* to compare JSON.
*
* @author Markus Lanthaler <mail@markus-lanthaler.com>
*/
abstract class JsonTestCase extends \PHPUnit_Framework_TestCase
{
/**
* Asserts that two JSON structures are equal.
*
* @param object|array $expected
* @param object|array $actual
* @param string $message
*/
public static function assertJsonEquals($expected, $actual, $message = '')
{
$expected = self::normalizeJson($expected);
$actual = self::normalizeJson($actual);
self::assertEquals($expected, $actual, $message);
}
/**
* Brings the keys of objects to a deterministic order to enable
* comparison of JSON structures
*
* @param mixed $element The element to normalize.
*
* @return mixed The same data with all object keys ordered in a
* deterministic way.
*/
private static function normalizeJson($element)
{
if (is_array($element)) {
foreach ($element as &$item) {
$item = self::normalizeJson($item);
}
} elseif (is_object($element)) {
$element = (array) $element;
ksort($element);
$element = (object) $element;
foreach ($element as &$item) {
$item = self::normalizeJson($item);
}
}
return $element;
}
}

106
vendor/ml/json-ld/Test/NQuadsTest.php vendored Normal file
View File

@@ -0,0 +1,106 @@
<?php
/*
* (c) Markus Lanthaler <mail@markus-lanthaler.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace ML\JsonLD\Test;
use ML\JsonLD\JsonLD;
use ML\JsonLD\NQuads;
/**
* Tests NQuads
*
* @author Markus Lanthaler <mail@markus-lanthaler.com>
*/
class NQuadsTest extends \PHPUnit_Framework_TestCase
{
/**
* Tests that parsing an invalid NQuad file fails
*
* @expectedException \ML\JsonLD\Exception\InvalidQuadException
*/
public function testInvalidParse()
{
$nquads = new NQuads();
$nquads->parse('Invalid NQuads file');
}
/**
* Tests escaping
*/
public function testEscaping()
{
$doc = '<http://example.com>';
$doc .= ' <http://schema.org/description>';
$doc .= ' "String with line-break \n and quote (\")" .';
$doc .= "\n";
$nquads = new NQuads();
$parsed = JsonLD::fromRdf($nquads->parse($doc));
$serialized = $nquads->serialize(JsonLD::toRdf($parsed));
$this->assertSame($doc, $serialized);
}
/**
* Tests blank node label parsing
*/
public function testParseBlankNodes()
{
$nquads = new NQuads();
$this->assertNotEmpty($nquads->parse('_:b <http://ex/1> "Test" .'), 'just a letter');
$this->assertNotEmpty($nquads->parse('_:b1 <http://ex/1> "Test" .'), 'letter and number');
$this->assertNotEmpty($nquads->parse('_:_b1 <http://ex/1> "Test" .'), 'beginning _');
$this->assertNotEmpty($nquads->parse('_:b_1 <http://ex/1> "Test" .'), 'containing _');
$this->assertNotEmpty($nquads->parse('_:b1_ <http://ex/1> "Test" .'), 'ending _');
$this->assertNotEmpty($nquads->parse('_:b-1 <http://ex/1> "Test" .'), 'containing -');
$this->assertNotEmpty($nquads->parse('_:b-1 <http://ex/1> "Test" .'), 'ending -');
$this->assertNotEmpty($nquads->parse('_:b.1 <http://ex/1> "Test" .'), 'containing .');
}
/**
* Tests that parsing fails for blank node labels beginning with "-"
*
* @expectedException \ML\JsonLD\Exception\InvalidQuadException
*/
public function testParseBlankNodeDashAtTheBeginning()
{
$nquads = new NQuads();
$nquads->parse('_:-b1 <http://ex/1> "Test" .');
}
/**
* Tests that parsing fails for blank node labels beginning with "."
*
* @expectedException \ML\JsonLD\Exception\InvalidQuadException
*/
public function testParseBlankNodePeriodAtTheBeginning()
{
$nquads = new NQuads();
$nquads->parse('_:.b1 <http://ex/1> "Test" .');
}
/**
* Tests that parsing fails for blank node labels ending with "."
*
* @expectedException \ML\JsonLD\Exception\InvalidQuadException
*/
public function testParseBlankNodePeriodAtTheEnd()
{
$nquads = new NQuads();
$nquads->parse('_:b1. <http://ex/1> "Test" .');
}
}

View File

@@ -0,0 +1,120 @@
<?php
/*
* (c) Markus Lanthaler <mail@markus-lanthaler.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace ML\JsonLD\Test;
/**
* TestManifestIterator reads a test manifest and returns the contained test
* definitions.
*
* @author Markus Lanthaler <mail@markus-lanthaler.com>
*/
class TestManifestIterator implements \Iterator
{
/** The current position. */
private $key = 0;
/** The test directory. */
private $directory;
/** The test manifest. */
private $manifest;
/** The URL of the test manifest. */
private $url;
/** The total number of tests. */
private $numberTests = 0;
/**
* Constructor
*
* @param string $file The manifest's filename.
* @param string $url The manifest's URL.
*/
public function __construct($file, $url)
{
if (file_exists($file)) {
$this->manifest = json_decode(file_get_contents($file));
$this->numberTests = count($this->manifest->{'sequence'});
$this->url = $url;
$this->directory = dirname($file) . DIRECTORY_SEPARATOR;
}
}
/**
* Rewinds the TestManifestIterator to the first element.
*/
public function rewind()
{
$this->key = 0;
}
/**
* Checks if current position is valid.
*
* @return bool True if the current position is valid; otherwise, false.
*/
public function valid()
{
return ($this->key < $this->numberTests);
}
/**
* Returns the key of the current element.
*
* @return string The key of the current element
*/
public function key()
{
return $this->url . $this->manifest->{'sequence'}[$this->key]->{'@id'};
}
/**
* Returns the current element.
*
* @return array Returns an array containing the name of the test and the
* test definition object.
*/
public function current()
{
$test = $this->manifest->{'sequence'}[$this->key];
$options = isset($test->{'option'})
? clone $test->{'option'} // cloning because we are modifying it
: new \stdClass();
if (false === property_exists($options, 'base')) {
if (property_exists($this->manifest, 'baseIri')) {
$options->base = $this->manifest->{'baseIri'} . $test->{'input'};
} else {
$options->base = $test->{'input'};
}
}
if (isset($options->{'expandContext'}) && (false === strpos($options->{'expandContext'}, ':'))) {
$options->{'expandContext'} = $this->directory . $options->{'expandContext'};
}
$test = array(
'name' => $test->{'name'},
'test' => $test,
'options' => $options
);
return $test;
}
/**
* Moves forward to next element.
*/
public function next()
{
$this->key++;
}
}

138
vendor/ml/json-ld/Test/ValueTest.php vendored Normal file
View File

@@ -0,0 +1,138 @@
<?php
/*
* (c) Markus Lanthaler <mail@markus-lanthaler.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace ML\JsonLD\Test;
use ML\JsonLD\LanguageTaggedString;
use ML\JsonLD\TypedValue;
/**
* Test LanguageTaggedString and TypedValue
*
* @author Markus Lanthaler <mail@markus-lanthaler.com>
*/
class ValueTest extends \PHPUnit_Framework_TestCase
{
/**
* Tests LanguageTaggedString
*/
public function testLanguageTaggedString()
{
$string1 = new LanguageTaggedString('', '');
$this->assertSame('', $string1->getValue(), 'string1 value');
$this->assertSame('', $string1->getLanguage(), 'string1 language');
$string2 = new LanguageTaggedString('wert', 'de');
$this->assertSame('wert', $string2->getValue(), 'string2 value');
$this->assertSame('de', $string2->getLanguage(), 'string2 language');
$string3 = new LanguageTaggedString('value', 'en');
$this->assertSame('value', $string3->getValue(), 'string3 value');
$this->assertSame('en', $string3->getLanguage(), 'string3 language');
}
/**
* Tests LanguageTaggedString with an invalid value
*
* @expectedException \InvalidArgumentException
*/
public function testLanguageTaggedStringInvalidValue()
{
$string1 = new LanguageTaggedString('value', 'language');
$string1->setValue(1);
}
/**
* Tests LanguageTaggedString with an invalid language
*
* @expectedException \InvalidArgumentException
*/
public function testLanguageTaggedStringInvalidLanguage()
{
$string1 = new LanguageTaggedString('value', 'language');
$string1->setLanguage(null);
}
/**
* Tests TypedValue
*/
public function testTypedValue()
{
$value1 = new TypedValue('', '');
$this->assertSame('', $value1->getValue(), 'string1 value');
$this->assertSame('', $value1->getType(), 'string1 type');
$value2 = new TypedValue('wert', 'http://example.com/type1');
$this->assertSame('wert', $value2->getValue(), 'string2 value');
$this->assertSame('http://example.com/type1', $value2->getType(), 'string2 type');
$value3 = new TypedValue('value', 'http://example.com/type2');
$this->assertSame('value', $value3->getValue(), 'string3 value');
$this->assertSame('http://example.com/type2', $value3->getType(), 'string3 type');
}
/**
* Tests TypedValue with an invalid value
*
* @expectedException \InvalidArgumentException
*/
public function testTypedValueInvalidValue()
{
$value1 = new LanguageTaggedString('value', 'language');
$value1->setValue(1);
}
/**
* Tests TypedValue with an invalid type
*
* @expectedException \InvalidArgumentException
*/
public function testTypedValueInvalidLanguage()
{
$value1 = new TypedValue('value', 'http://example.com/type');
$value1->setType(1);
}
/**
* Tests TypedValue with an invalid type
*/
public function testEquals()
{
$string1a = new LanguageTaggedString('value', 'en');
$string1b = new LanguageTaggedString('value', 'en');
$string2 = new LanguageTaggedString('value', 'de');
$string3 = new LanguageTaggedString('wert', 'en');
$this->assertTrue($string1a->equals($string1b), 's1a == s1b?');
$this->assertFalse($string1a->equals($string2), 's1a == s2?');
$this->assertFalse($string1a->equals($string3), 's1a == s3?');
$this->assertFalse($string1b->equals($string2), 's1b == s2?');
$this->assertFalse($string1b->equals($string3), 's1b == s3?');
$this->assertFalse($string2->equals($string3), 's2 == s3?');
$typed1a = new TypedValue('value', 'http://example.com/type1');
$typed1b = new TypedValue('value', 'http://example.com/type1');
$typed2 = new TypedValue('value', 'http://example.com/type2');
$typed3 = new TypedValue('wert', 'http://example.com/type1');
$this->assertTrue($typed1a->equals($typed1b), 't1a == t1b?');
$this->assertFalse($typed1a->equals($typed2), 't1a == t2?');
$this->assertFalse($typed1a->equals($typed3), 't1a == t3?');
$this->assertFalse($typed1b->equals($typed2), 't1b == t2?');
$this->assertFalse($typed1b->equals($typed3), 't1b == t3?');
$this->assertFalse($typed2->equals($typed3), 't2 == t3?');
$string4 = new LanguageTaggedString('', '');
$typed4 = new TypedValue('', '');
$this->assertFalse($string4->equals($typed4), 's4 == t4');
$this->assertFalse($typed4->equals($string4), 's4 == t4');
}
}

View File

@@ -0,0 +1,368 @@
<?php
/*
* (c) Markus Lanthaler <mail@markus-lanthaler.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace ML\JsonLD\Test;
use ML\JsonLD\JsonLD;
use ML\JsonLD\NQuads;
use ML\JsonLD\Test\TestManifestIterator;
/**
* The official W3C JSON-LD test suite.
*
* @link http://www.w3.org/2013/json-ld-tests/ Official W3C JSON-LD test suite
*
* @author Markus Lanthaler <mail@markus-lanthaler.com>
*/
class W3CTestSuiteTest extends JsonTestCase
{
/**
* The base directory from which the test manifests, input, and output
* files should be read.
*/
private $basedir;
/**
* The URL corresponding to the base directory
*/
private $baseurl = 'http://json-ld.org/test-suite/tests/';
/**
* @var string The test's ID.
*/
private $id;
/**
* Constructs a test case with the given name.
*
* @param null|string $name
* @param array $data
* @param string $dataName
*/
public function __construct($name = null, array $data = array(), $dataName = '')
{
$this->id = $dataName;
parent::__construct($name, $data, $dataName);
$this->basedir = dirname(__FILE__) . '/../vendor/json-ld/tests/';
}
/**
* Returns the test identifier.
*
* @return string The test identifier
*/
public function getTestId()
{
return $this->id;
}
/**
* Tests expansion.
*
* @param string $name The test name.
* @param object $test The test definition.
* @param object $options The options to configure the algorithms.
*
* @group expansion
* @dataProvider expansionProvider
*/
public function testExpansion($name, $test, $options)
{
$expected = json_decode(file_get_contents($this->basedir . $test->{'expect'}));
$result = JsonLD::expand($this->basedir . $test->{'input'}, $options);
$this->assertJsonEquals($expected, $result);
}
/**
* Provides expansion test cases.
*/
public function expansionProvider()
{
return new TestManifestIterator(
$this->basedir . 'expand-manifest.jsonld',
$this->baseurl . 'expand-manifest.jsonld'
);
}
/**
* Tests compaction.
*
* @param string $name The test name.
* @param object $test The test definition.
* @param object $options The options to configure the algorithms.
*
* @group compaction
* @dataProvider compactionProvider
*/
public function testCompaction($name, $test, $options)
{
$expected = json_decode(file_get_contents($this->basedir . $test->{'expect'}));
$result = JsonLD::compact(
$this->basedir . $test->{'input'},
$this->basedir . $test->{'context'},
$options
);
$this->assertJsonEquals($expected, $result);
}
/**
* Provides compaction test cases.
*/
public function compactionProvider()
{
return new TestManifestIterator(
$this->basedir . 'compact-manifest.jsonld',
$this->baseurl . 'compact-manifest.jsonld'
);
}
/**
* Tests flattening.
*
* @param string $name The test name.
* @param object $test The test definition.
* @param object $options The options to configure the algorithms.
*
* @group flattening
* @dataProvider flattenProvider
*/
public function testFlatten($name, $test, $options)
{
$expected = json_decode(file_get_contents($this->basedir . $test->{'expect'}));
$context = (isset($test->{'context'}))
? $this->basedir . $test->{'context'}
: null;
$result = JsonLD::flatten($this->basedir . $test->{'input'}, $context, $options);
$this->assertJsonEquals($expected, $result);
}
/**
* Provides flattening test cases.
*/
public function flattenProvider()
{
return new TestManifestIterator(
$this->basedir . 'flatten-manifest.jsonld',
$this->baseurl . 'flatten-manifest.jsonld'
);
}
/**
* Tests remote document loading.
*
* @param string $name The test name.
* @param object $test The test definition.
* @param object $options The options to configure the algorithms.
*
* @group remote
* @dataProvider remoteDocumentLoadingProvider
*/
public function testRemoteDocumentLoading($name, $test, $options)
{
if (in_array('jld:NegativeEvaluationTest', $test->{'@type'})) {
$this->setExpectedException('ML\JsonLD\Exception\JsonLdException', null, $test->{'expect'});
} else {
$expected = json_decode($this->replaceBaseUrl(file_get_contents($this->basedir . $test->{'expect'})));
}
unset($options->base);
$result = JsonLD::expand($this->replaceBaseUrl($this->baseurl . $test->{'input'}), $options);
if (isset($expected)) {
$this->assertJsonEquals($expected, $result);
}
}
/**
* Provides remote document loading test cases.
*/
public function remoteDocumentLoadingProvider()
{
return new TestManifestIterator(
$this->basedir . 'remote-doc-manifest.jsonld',
$this->baseurl . 'remote-doc-manifest.jsonld'
);
}
/**
* Replaces the base URL 'http://json-ld.org/' with 'https://json-ld.org:443/'.
*
* The test location of the test suite has been changed as the site has been
* updated to use HTTPS everywhere.
*
* @param string $input The input string.
*
* @return string The input string with all occurrences of the old base URL replaced with the new HTTPS-based one.
*/
private function replaceBaseUrl($input) {
return str_replace('http://json-ld.org/', 'https://json-ld.org:443/', $input);
}
/**
* Tests errors (uses flattening).
*
* @param string $name The test name.
* @param object $test The test definition.
* @param object $options The options to configure the algorithms.
*
* @group errors
* @dataProvider errorProvider
*/
public function testError($name, $test, $options)
{
$this->setExpectedException('ML\JsonLD\Exception\JsonLdException', null, $test->{'expect'});
JsonLD::flatten(
$this->basedir . $test->{'input'},
(isset($test->{'context'})) ? $this->basedir . $test->{'context'} : null,
$options
);
}
/**
* Provides error test cases.
*/
public function errorProvider()
{
return new TestManifestIterator(
$this->basedir . 'error-manifest.jsonld',
$this->baseurl . 'error-manifest.jsonld'
);
}
/**
* Tests framing.
*
* @param string $name The test name.
* @param object $test The test definition.
* @param object $options The options to configure the algorithms.
*
* @group framing
* @dataProvider framingProvider
*/
public function testFraming($name, $test, $options)
{
$ignoredTests = array(
'frame-0005-in.jsonld',
'frame-0009-in.jsonld',
'frame-0010-in.jsonld',
'frame-0012-in.jsonld',
'frame-0013-in.jsonld',
'frame-0023-in.jsonld',
'frame-0024-in.jsonld',
'frame-0027-in.jsonld',
'frame-0028-in.jsonld',
'frame-0029-in.jsonld',
'frame-0030-in.jsonld'
);
if (in_array($test->{'input'}, $ignoredTests)) {
$this->markTestSkipped(
'This implementation uses deep value matching and aggressive re-embedding. See ISSUE-110 and ISSUE-119.'
);
}
$expected = json_decode(file_get_contents($this->basedir . $test->{'expect'}));
$result = JsonLD::frame(
$this->basedir . $test->{'input'},
$this->basedir . $test->{'frame'},
$options
);
$this->assertJsonEquals($expected, $result);
}
/**
* Provides framing test cases.
*/
public function framingProvider()
{
return new TestManifestIterator(
$this->basedir . 'frame-manifest.jsonld',
$this->baseurl . 'frame-manifest.jsonld'
);
}
/**
* Tests conversion to RDF quads.
*
* @param string $name The test name.
* @param object $test The test definition.
* @param object $options The options to configure the algorithms.
*
* @group toRdf
* @dataProvider toRdfProvider
*/
public function testToRdf($name, $test, $options)
{
$expected = trim(file_get_contents($this->basedir . $test->{'expect'}));
$quads = JsonLD::toRdf($this->basedir . $test->{'input'}, $options);
$serializer = new NQuads();
$result = $serializer->serialize($quads);
// Sort quads (the expected quads are already sorted)
$result = explode("\n", trim($result));
sort($result);
$result = implode("\n", $result);
$this->assertEquals($expected, $result);
}
/**
* Provides conversion to RDF quads test cases.
*/
public function toRdfProvider()
{
return new TestManifestIterator(
$this->basedir . 'toRdf-manifest.jsonld',
$this->baseurl . 'toRdf-manifest.jsonld'
);
}
/**
* Tests conversion from quads.
*
* @param string $name The test name.
* @param object $test The test definition.
* @param object $options The options to configure the algorithms.
*
* @group fromRdf
* @dataProvider fromRdfProvider
*/
public function testFromRdf($name, $test, $options)
{
$expected = json_decode(file_get_contents($this->basedir . $test->{'expect'}));
$parser = new NQuads();
$quads = $parser->parse(file_get_contents($this->basedir . $test->{'input'}));
$result = JsonLD::fromRdf($quads, $options);
$this->assertEquals($expected, $result);
}
/**
* Provides conversion to quads test cases.
*/
public function fromRdfProvider()
{
return new TestManifestIterator(
$this->basedir . 'fromRdf-manifest.jsonld',
$this->baseurl . 'fromRdf-manifest.jsonld'
);
}
}

19
vendor/ml/json-ld/Test/bootstrap.php vendored Normal file
View File

@@ -0,0 +1,19 @@
<?php
if (!@include(__DIR__ . '/../vendor/autoload.php')) {
spl_autoload_register(
function ($class) {
if (0 === strpos($class, 'ML\\JsonLD\\')) {
$path = implode('/', array_slice(explode('\\', $class), 2)) . '.php';
require_once __DIR__ . '/../' . $path;
return true;
} elseif (0 === strpos($class, 'ML\\IRI\\')) {
$path = implode('/', array_slice(explode('\\', $class), 2)) . '.php';
require_once __DIR__ . '/../../IRI/' . $path;
return true;
}
}
);
}

139
vendor/ml/json-ld/TypedValue.php vendored Normal file
View File

@@ -0,0 +1,139 @@
<?php
/*
* (c) Markus Lanthaler <mail@markus-lanthaler.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace ML\JsonLD;
use stdClass as JsonObject;
/**
* A typed value represents a value with an associated type.
*
* @author Markus Lanthaler <mail@markus-lanthaler.com>
*/
final class TypedValue extends Value
{
/**
* The type of the value in the form of an IRI.
*
* @var string
*/
private $type;
/**
* Constructor
*
* @param string $value The value.
* @param string $type The type.
*/
public function __construct($value, $type)
{
$this->setValue($value);
$this->setType($type);
}
/**
* Set the type
*
* For the sake of simplicity, the type is currently just a Node
* identifier in the form of a string and not a Node reference.
* This might be changed in the future.
*
* @param string $type The type.
*
* @return self
*
* @throws \InvalidArgumentException If the type is not a string. No
* further checks are currently done.
*/
public function setType($type)
{
if (!is_string($type)) {
throw new \InvalidArgumentException('type must be a string.');
}
$this->type = $type;
return $this;
}
/**
* Get the type
*
* For the sake of simplicity, the type is currently just a Node
* identifier in the form of a string and not a Node reference.
* This might be changed in the future.
*
* @return string The type.
*/
public function getType()
{
return $this->type;
}
/**
* {@inheritdoc}
*/
public function toJsonLd($useNativeTypes = true)
{
$result = new JsonObject();
if (RdfConstants::XSD_STRING === $this->type) {
$result->{'@value'} = $this->value;
return $result;
}
if (true === $useNativeTypes) {
if (RdfConstants::XSD_BOOLEAN === $this->type) {
if ('true' === $this->value) {
$result->{'@value'} = true;
return $result;
} elseif ('false' === $this->value) {
$result->{'@value'} = false;
return $result;
}
} elseif (RdfConstants::XSD_INTEGER === $this->type) {
if (preg_match('/^[\+|-]?\d+$/', trim($this->value))) {
$result->{'@value'} = intval($this->value);
return $result;
}
} elseif (RdfConstants::XSD_DOUBLE === $this->type) {
// TODO Need to handle +/-INF and NaN as well?
if (preg_match('/^[\+|-]?\d+(?:\.\d*)?(?:[eE][\+|-]?\d+)?$/', trim($this->value))) {
$result->{'@value'} = floatval($this->value);
return $result;
}
// TODO Need to preserve doubles without fraction for round-tripping??
}
}
$result->{'@value'} = $this->value;
$result->{'@type'} = $this->type;
return $result;
}
/**
* {@inheritdoc}
*/
public function equals($other)
{
if (get_class($this) !== get_class($other)) {
return false;
}
return ($this->value === $other->value) && ($this->type === $other->type);
}
}

123
vendor/ml/json-ld/Value.php vendored Normal file
View File

@@ -0,0 +1,123 @@
<?php
/*
* (c) Markus Lanthaler <mail@markus-lanthaler.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace ML\JsonLD;
use stdClass as JsonObject;
/**
* Value is the abstract base class used for typed values and
* language-tagged strings.
*
* @author Markus Lanthaler <mail@markus-lanthaler.com>
*/
abstract class Value implements JsonLdSerializable
{
/**
* The value in the form of a string
*
* @var string
*/
protected $value;
/**
* Set the value
*
* @param string $value The value.
*
* @return self
*
* @throws \InvalidArgumentException If the value is not a string.
*/
public function setValue($value)
{
if (!is_string($value)) {
throw new \InvalidArgumentException('value must be a string.');
}
$this->value = $value;
return $this;
}
/**
* Get the value
*
* @return string The value.
*/
public function getValue()
{
return $this->value;
}
/**
* Create a LanguageTaggedString or TypedValue from a JSON-LD element
*
* If the passed value element can't be transformed to a language-tagged
* string or a typed value false is returned.
*
* @param JsonObject $element The JSON-LD element
*
* @return false|LanguageTaggedString|TypedValue The parsed object
*/
public static function fromJsonLd(JsonObject $element)
{
if (false === property_exists($element, '@value')) {
return false;
}
$value = $element->{'@value'};
$type = (property_exists($element, '@type'))
? $element->{'@type'}
: null;
$language = (property_exists($element, '@language'))
? $element->{'@language'}
: null;
if (is_int($value) || is_float($value)) {
if (($value != (int) $value) || (RdfConstants::XSD_DOUBLE === $type)) {
$value = preg_replace('/(0{0,14})E(\+?)/', 'E', sprintf('%1.15E', $value));
if ((null === $type) && (null === $language)) {
return new TypedValue($value, RdfConstants::XSD_DOUBLE);
}
} else {
$value = sprintf('%d', $value);
if ((null === $type) && (null === $language)) {
return new TypedValue($value, RdfConstants::XSD_INTEGER);
}
}
} elseif (is_bool($value)) {
$value = ($value) ? 'true' : 'false';
if ((null === $type) && (null === $language)) {
return new TypedValue($value, RdfConstants::XSD_BOOLEAN);
}
} elseif (false === is_string($value)) {
return false;
}
// @type gets precedence
if ((null === $type) && (null !== $language)) {
return new LanguageTaggedString($value, $language);
}
return new TypedValue($value, (null === $type) ? RdfConstants::XSD_STRING : $type);
}
/**
* Compares this instance to the specified value.
*
* @param mixed $other The value this instance should be compared to.
*
* @return bool Returns true if the passed value is the same as this
* instance; false otherwise.
*/
abstract public function equals($other);
}

30
vendor/ml/json-ld/composer.json vendored Normal file
View File

@@ -0,0 +1,30 @@
{
"name": "ml/json-ld",
"type": "library",
"description": "JSON-LD Processor for PHP",
"keywords": [ "JSON-LD", "jsonld" ],
"homepage": "http://www.markus-lanthaler.com",
"license": "MIT",
"authors": [
{
"name": "Markus Lanthaler",
"email": "mail@markus-lanthaler.com",
"homepage": "http://www.markus-lanthaler.com",
"role": "Developer"
}
],
"require": {
"php": ">=5.3.0",
"ext-json": "*",
"ml/iri": "^1.1.1"
},
"require-dev": {
"json-ld/tests": "1.0",
"phpunit/phpunit": "^4"
},
"autoload": {
"psr-4": {
"ML\\JsonLD\\": ""
}
}
}

74
vendor/ml/json-ld/phpunit.xml.dist vendored Normal file
View File

@@ -0,0 +1,74 @@
<?xml version="1.0" encoding="UTF-8"?>
<phpunit backupGlobals="false"
backupStaticAttributes="false"
colors="true"
convertErrorsToExceptions="true"
convertNoticesToExceptions="true"
convertWarningsToExceptions="true"
processIsolation="false"
stopOnFailure="false"
strict="true"
bootstrap="./Test/bootstrap.php">
<testsuites>
<testsuite name="JsonLD Test Suite">
<directory suffix="Test.php">./Test/</directory>
</testsuite>
</testsuites>
<filter>
<whitelist processUncoveredFilesFromWhitelist="true">
<directory>./</directory>
<exclude>
<directory>./Test</directory>
<directory>./vendor</directory>
</exclude>
</whitelist>
</filter>
<!-- Uncomment this section if you want to generate an EARL implementation report
<listeners>
<listener class="\ML\JsonLD\Test\EarlReportGenerator">
<arguments>
<array>
<element key="target">
<string>earl-report.jsonld</string>
</element>
<element key="project-name">
<string>JsonLD</string>
</element>
<element key="project-url">
<string>https://github.com/lanthaler/JsonLD</string>
</element>
<element key="project-homepage">
<string>https://github.com/lanthaler/JsonLD</string>
</element>
<element key="license-url">
<string>https://raw.github.com/lanthaler/JsonLD/master/LICENSE</string>
</element>
<element key="project-description">
<string>JSON-LD processor for PHP</string>
</element>
<element key="programming-language">
<string>PHP</string>
</element>
<element key="developer-name">
<string>Markus Lanthaler</string>
</element>
<element key="developer-url">
<string>http://me.markus-lanthaler.com</string>
</element>
<element key="developer-homepage">
<string>http://www.markus-lanthaler.com/</string>
</element>
</array>
</arguments>
</listener>
</listeners>
-->
<logging>
<log type="coverage-text" target="php://stdout" showUncoveredFiles="true" />
</logging>
</phpunit>