@@ -94,6 +94,7 @@ function jsonld_flatten($input, $ctx, $options=array()) {
94
94
* [base] the base IRI to use.
95
95
* [embed] default @embed flag (default: true).
96
96
* [explicit] default @explicit flag (default: false).
97
+ * [requireAll] default @requireAll flag (default: true).
97
98
* [omitDefault] default @omitDefault flag (default: false).
98
99
* [documentLoader(url)] the document loader.
99
100
*
@@ -1076,6 +1077,7 @@ public function flatten($input, $ctx, $options) {
1076
1077
* [expandContext] a context to expand with.
1077
1078
* [embed] default @embed flag (default: true).
1078
1079
* [explicit] default @explicit flag (default: false).
1080
+ * [requireAll] default @requireAll flag (default: true).
1079
1081
* [omitDefault] default @omitDefault flag (default: false).
1080
1082
* [documentLoader(url)] the document loader.
1081
1083
*
@@ -1088,6 +1090,7 @@ public function frame($input, $frame, $options) {
1088
1090
'compactArrays ' => true ,
1089
1091
'embed ' => true ,
1090
1092
'explicit ' => false ,
1093
+ 'requireAll ' => true ,
1091
1094
'omitDefault ' => false ,
1092
1095
'documentLoader ' => $ jsonld_default_load_document ));
1093
1096
@@ -3679,13 +3682,18 @@ protected function _matchFrame(
3679
3682
$ this ->_validateFrame ($ state , $ frame );
3680
3683
$ frame = $ frame [0 ];
3681
3684
3682
- // filter out subjects that match the frame
3683
- $ matches = $ this ->_filterSubjects ($ state , $ subjects , $ frame );
3684
-
3685
3685
// get flags for current frame
3686
3686
$ options = $ state ->options ;
3687
3687
$ embed_on = $ this ->_getFrameFlag ($ frame , $ options , 'embed ' );
3688
3688
$ 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 );
3689
3697
3690
3698
// add matches to output
3691
3699
foreach ($ matches as $ id => $ subject ) {
@@ -3859,15 +3867,16 @@ protected function _validateFrame($state, $frame) {
3859
3867
* @param stdClass $state the current framing state.
3860
3868
* @param array $subjects the set of subjects to filter.
3861
3869
* @param stdClass $frame the parsed frame.
3870
+ * @param assoc $flags the frame flags.
3862
3871
*
3863
3872
* @return stdClass all of the matched subjects.
3864
3873
*/
3865
- protected function _filterSubjects ($ state , $ subjects , $ frame ) {
3874
+ protected function _filterSubjects ($ state , $ subjects , $ frame, $ flags ) {
3866
3875
$ rval = new stdClass ();
3867
3876
sort ($ subjects );
3868
3877
foreach ($ subjects as $ id ) {
3869
3878
$ subject = $ state ->subjects ->{$ id };
3870
- if ($ this ->_filterSubject ($ subject , $ frame )) {
3879
+ if ($ this ->_filterSubject ($ subject , $ frame, $ flags )) {
3871
3880
$ rval ->{$ id } = $ subject ;
3872
3881
}
3873
3882
}
@@ -3879,10 +3888,11 @@ protected function _filterSubjects($state, $subjects, $frame) {
3879
3888
*
3880
3889
* @param stdClass $subject the subject to check.
3881
3890
* @param stdClass $frame the frame to check.
3891
+ * @param assoc $flags the frame flags.
3882
3892
*
3883
3893
* @return bool true if the subject matches, false if not.
3884
3894
*/
3885
- protected function _filterSubject ($ subject , $ frame ) {
3895
+ protected function _filterSubject ($ subject , $ frame, $ flags ) {
3886
3896
// check @type (object value means 'any' type, fall through to ducktyping)
3887
3897
if (property_exists ($ frame , '@type ' ) &&
3888
3898
!(count ($ frame ->{'@type ' }) === 1 && is_object ($ frame ->{'@type ' }[0 ]))) {
@@ -3897,14 +3907,47 @@ protected function _filterSubject($subject, $frame) {
3897
3907
}
3898
3908
3899
3909
// check ducktype
3910
+ $ wildcard = true ;
3911
+ $ matches_some = false ;
3900
3912
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 ) {
3904
3945
return false ;
3905
3946
}
3906
3947
}
3907
- return true ;
3948
+
3949
+ // return true if wildcard or subject matches some properties
3950
+ return $ wildcard || $ matches_some ;
3908
3951
}
3909
3952
3910
3953
/**
@@ -5325,6 +5368,7 @@ protected static function _isKeyword($v) {
5325
5368
case '@list ' :
5326
5369
case '@omitDefault ' :
5327
5370
case '@preserve ' :
5371
+ case '@requireAll ' :
5328
5372
case '@reverse ' :
5329
5373
case '@set ' :
5330
5374
case '@type ' :
0 commit comments