Skip to content

Commit 3402d51

Browse files
committed
Add new framing features.
- Allow filtering based on a specific @id. - Allow ducktyping matches on @type: [{}]. - Allow ducktyping matches when a @default is specified. - Add @requireAll flag for controlling ducktyping requirements.
1 parent ba16da5 commit 3402d51

File tree

1 file changed

+54
-10
lines changed

1 file changed

+54
-10
lines changed

jsonld.php

Lines changed: 54 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,7 @@ function jsonld_flatten($input, $ctx, $options=array()) {
9494
* [base] the base IRI to use.
9595
* [embed] default @embed flag (default: true).
9696
* [explicit] default @explicit flag (default: false).
97+
* [requireAll] default @requireAll flag (default: true).
9798
* [omitDefault] default @omitDefault flag (default: false).
9899
* [documentLoader(url)] the document loader.
99100
*
@@ -1076,6 +1077,7 @@ public function flatten($input, $ctx, $options) {
10761077
* [expandContext] a context to expand with.
10771078
* [embed] default @embed flag (default: true).
10781079
* [explicit] default @explicit flag (default: false).
1080+
* [requireAll] default @requireAll flag (default: true).
10791081
* [omitDefault] default @omitDefault flag (default: false).
10801082
* [documentLoader(url)] the document loader.
10811083
*
@@ -1088,6 +1090,7 @@ public function frame($input, $frame, $options) {
10881090
'compactArrays' => true,
10891091
'embed' => true,
10901092
'explicit' => false,
1093+
'requireAll' => true,
10911094
'omitDefault' => false,
10921095
'documentLoader' => $jsonld_default_load_document));
10931096

@@ -3679,13 +3682,18 @@ protected function _matchFrame(
36793682
$this->_validateFrame($state, $frame);
36803683
$frame = $frame[0];
36813684

3682-
// filter out subjects that match the frame
3683-
$matches = $this->_filterSubjects($state, $subjects, $frame);
3684-
36853685
// get flags for current frame
36863686
$options = $state->options;
36873687
$embed_on = $this->_getFrameFlag($frame, $options, 'embed');
36883688
$explicit_on = $this->_getFrameFlag($frame, $options, 'explicit');
3689+
$require_all_on = $this->_getFrameFlag($frame, $options, 'requireAll');
3690+
$flags = array(
3691+
'embed' => $embed_on,
3692+
'explicit' => $explicit_on,
3693+
'requireAll' => $require_all_on);
3694+
3695+
// filter out subjects that match the frame
3696+
$matches = $this->_filterSubjects($state, $subjects, $frame, $flags);
36893697

36903698
// add matches to output
36913699
foreach($matches as $id => $subject) {
@@ -3859,15 +3867,16 @@ protected function _validateFrame($state, $frame) {
38593867
* @param stdClass $state the current framing state.
38603868
* @param array $subjects the set of subjects to filter.
38613869
* @param stdClass $frame the parsed frame.
3870+
* @param assoc $flags the frame flags.
38623871
*
38633872
* @return stdClass all of the matched subjects.
38643873
*/
3865-
protected function _filterSubjects($state, $subjects, $frame) {
3874+
protected function _filterSubjects($state, $subjects, $frame, $flags) {
38663875
$rval = new stdClass();
38673876
sort($subjects);
38683877
foreach($subjects as $id) {
38693878
$subject = $state->subjects->{$id};
3870-
if($this->_filterSubject($subject, $frame)) {
3879+
if($this->_filterSubject($subject, $frame, $flags)) {
38713880
$rval->{$id} = $subject;
38723881
}
38733882
}
@@ -3879,10 +3888,11 @@ protected function _filterSubjects($state, $subjects, $frame) {
38793888
*
38803889
* @param stdClass $subject the subject to check.
38813890
* @param stdClass $frame the frame to check.
3891+
* @param assoc $flags the frame flags.
38823892
*
38833893
* @return bool true if the subject matches, false if not.
38843894
*/
3885-
protected function _filterSubject($subject, $frame) {
3895+
protected function _filterSubject($subject, $frame, $flags) {
38863896
// check @type (object value means 'any' type, fall through to ducktyping)
38873897
if(property_exists($frame, '@type') &&
38883898
!(count($frame->{'@type'}) === 1 && is_object($frame->{'@type'}[0]))) {
@@ -3897,14 +3907,47 @@ protected function _filterSubject($subject, $frame) {
38973907
}
38983908

38993909
// check ducktype
3910+
$wildcard = true;
3911+
$matches_some = false;
39003912
foreach($frame as $k => $v) {
3901-
// only not a duck if @id or non-keyword isn't in subject
3902-
if(($k === '@id' || !self::_isKeyword($k)) &&
3903-
!property_exists($subject, $k)) {
3913+
if(self::_isKeyword($k)) {
3914+
// skip non-@id and non-@type
3915+
if($k !== '@id' && $k !== '@type') {
3916+
continue;
3917+
}
3918+
$wildcard = false;
3919+
3920+
// check @id for a specific @id value
3921+
if($k === '@id' && is_string($v)) {
3922+
if(!property_exists($subject, $k) || $subject->{$k} !== $v) {
3923+
return false;
3924+
}
3925+
$matches_some = true;
3926+
continue;
3927+
}
3928+
}
3929+
3930+
$wildcard = false;
3931+
3932+
if(property_exists($subject, $k)) {
3933+
// $v === [] means do not match if property is present
3934+
if(is_array($v) && count($v) === 0) {
3935+
return false;
3936+
}
3937+
$matches_some = true;
3938+
continue;
3939+
}
3940+
3941+
// all properties must match to be a duck unless a @default is specified
3942+
$has_default = (is_array($v) && count($v) === 1 && is_object($v[0]) &&
3943+
property_exists($v[0], '@default'));
3944+
if($flags['requireAll'] && !$has_default) {
39043945
return false;
39053946
}
39063947
}
3907-
return true;
3948+
3949+
// return true if wildcard or subject matches some properties
3950+
return $wildcard || $matches_some;
39083951
}
39093952

39103953
/**
@@ -5325,6 +5368,7 @@ protected static function _isKeyword($v) {
53255368
case '@list':
53265369
case '@omitDefault':
53275370
case '@preserve':
5371+
case '@requireAll':
53285372
case '@reverse':
53295373
case '@set':
53305374
case '@type':

0 commit comments

Comments
 (0)