Skip to content
GitLab
Menu
Projects
Groups
Snippets
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in
Toggle navigation
Menu
Open sidebar
project
subrequests
Commits
970a679e
Unverified
Commit
970a679e
authored
Mar 21, 2017
by
Mateu Aguiló Bosch
Browse files
Support more complex trees
parent
8a63860c
Changes
2
Hide whitespace changes
Inline
Side-by-side
src/Blueprint/RequestTree.php
View file @
970a679e
...
...
@@ -3,8 +3,8 @@
namespace
Drupal\subrequests\Blueprint
;
use
Drupal\Component\Serialization\Json
;
use
Rs\Json\Pointer
;
use
Rs\Json\Pointer\NonexistentValueReferencedException
;
use
Symfony\Component\HttpFoundation\Request
;
use
Symfony\Component\HttpFoundation\Response
;
...
...
@@ -147,43 +147,28 @@ class RequestTree {
*/
public
function
dereference
(
array
$responses
)
{
$this
->
requests
=
array_map
(
function
(
Request
$request
)
use
(
$responses
)
{
$subrequest_id
=
$request
->
attributes
->
get
(
static
::
SUBREQUEST_ID
);
// Detect {{/foo#/bar}}
$pattern
=
'/\{\{\/([^\{\}]+)@(\/[^\{\}]+)\}\}/'
;
$id
=
$request
->
attributes
->
get
(
static
::
SUBREQUEST_ID
);
$parent_id
=
$request
->
attributes
->
get
(
static
::
SUBREQUEST_PARENT_ID
);
// Allow replacement tokens in:
// 1. The body.
// 2. The path.
// 3. The query string values.
$matches
=
[];
if
(
preg_match
(
$pattern
,
$request
->
getContent
(),
$matches
))
{
// Do the magic.
$matches
;
$content
=
$request
->
getContent
();
$changes
=
static
::
replaceAllOccurrences
(
$responses
,
$content
);
$uri
=
$request
->
getUri
();
$changes
+=
static
::
replaceAllOccurrences
(
$responses
,
$uri
);
foreach
(
$request
->
query
as
$key
=>
$value
)
{
$changes
+=
static
::
replaceAllOccurrences
(
$responses
,
$value
);
$request
->
query
->
set
(
$key
,
$value
);
}
$matches
=
[];
if
(
preg_match
(
$pattern
,
$request
->
getRequestUri
(),
$matches
))
{
$replacement
=
static
::
findReplacement
(
$responses
,
$matches
[
1
],
$matches
[
2
]);
$new_uri
=
preg_replace
(
$pattern
,
$replacement
,
$request
->
getRequestUri
());
$request
->
server
->
set
(
'REQUEST_URI'
,
$new_uri
);
// If there is anything to update.
if
(
$changes
)
{
// We need to duplicate the request to force recomputing the internal
// caches.
$request
=
Request
::
create
(
$new_uri
,
$request
->
getMethod
(),
(
array
)
$request
->
query
->
getIterator
(),
(
array
)
$request
->
cookies
->
getIterator
(),
(
array
)
$request
->
files
->
getIterator
(),
(
array
)
$request
->
server
->
getIterator
(),
$request
->
getContent
()
);
$request
->
headers
->
set
(
'Content-ID'
,
sprintf
(
'<%s>'
,
$subrequest_id
));
}
foreach
(
$request
->
query
as
$key
=>
$value
)
{
$matches
=
[];
if
(
preg_match
(
$pattern
,
$request
->
getUri
(),
$matches
))
{
// Do the magic.
$matches
;
}
$request
=
static
::
cloneRequest
(
$request
,
$uri
,
$content
,
$id
,
$parent_id
);
}
return
$request
;
},
$this
->
getRequests
());
}
...
...
@@ -213,15 +198,108 @@ class RequestTree {
return
TRUE
;
}
protected
static
function
findReplacement
(
$responses
,
$id
,
$json_pointer_path
)
{
/** @var \Symfony\Component\HttpFoundation\Response $response */
$response
=
array_filter
(
$responses
,
function
(
Response
$response
)
use
(
$id
)
{
/**
* Do in-place replacements for an input string containing replacement tokens.
*
* @param array $responses
* The pool of responses where to find the replacement data.
* @param string $input
* The string containing the token to replace. It's passed by reference and
* modified if necessary.
*
* @return int
* The number of replacements made.
*/
public
static
function
replaceAllOccurrences
(
array
$responses
,
&
$input
)
{
// Detect {{/foo#/bar}}
$pattern
=
'/\{\{\/([^\{\}]+)@(\/[^\{\}]+)\}\}/'
;
$matches
=
[];
if
(
!
preg_match_all
(
$pattern
,
$input
,
$matches
))
{
return
0
;
}
for
(
$index
=
0
;
$index
<
count
(
$matches
[
1
]);
$index
++
)
{
$replacement
=
static
::
findReplacement
(
$responses
,
$matches
[
1
][
$index
],
$matches
[
2
][
$index
]
);
$pattern
=
sprintf
(
'/%s/'
,
preg_quote
(
$matches
[
0
][
$index
],
'/'
));
$input
=
preg_replace
(
$pattern
,
$replacement
,
$input
);
}
return
$index
;
}
/**
* Find a replacement in the responses for the JSON pointer.
*
* @param \Symfony\Component\HttpFoundation\Response[] $responses
* The array of responses to look data into.
* @param string $id
* The response ID to extract data from.
* @param $json_pointer_path
* The JSON pointer path of the data to extract.
*
* @throws \Rs\Json\Pointer\NonexistentValueReferencedException
* When the referenced response was not found.
*
* @return mixed
* The contents of the pointed JSON property.
*/
protected
static
function
findReplacement
(
array
$responses
,
$id
,
$json_pointer_path
)
{
$found
=
array_filter
(
$responses
,
function
(
Response
$response
)
use
(
$id
)
{
return
$response
->
headers
->
get
(
'Content-ID'
)
===
sprintf
(
'<%s>'
,
$id
);
})[
0
];
});
$response
=
reset
(
$found
);
if
(
!
$response
instanceof
Response
)
{
throw
new
NonexistentValueReferencedException
(
'Response is still not ready.'
);
}
// Find the data in the response output.
$pointer
=
new
Pointer
(
$response
->
getContent
());
return
$pointer
->
get
(
$json_pointer_path
);
}
/**
* Clones a request and modifies certain parameters.
*
* We need to do this to reset some of the internal request caches. There may
* be a better way of doing this, but I could not find it in the time that I
* expected.
*
* @param \Symfony\Component\HttpFoundation\Request $request
* The original request.
* @param $uri
* The (potentially) new URI.
* @param $content
* The (potentially) new body content.
* @param $id
* The subrequest id.
* @param $parent_id
* The subrequest id of the parent.
*
* @return \Symfony\Component\HttpFoundation\Request
* The cloned request.
*/
protected
static
function
cloneRequest
(
Request
$request
,
$uri
,
$content
,
$id
,
$parent_id
)
{
$request
->
server
->
set
(
'REQUEST_URI'
,
$uri
);
$sub_tree
=
$request
->
attributes
->
get
(
static
::
SUBREQUEST_TREE
);
$session
=
$request
->
getSession
();
$new_request
=
Request
::
create
(
$uri
,
$request
->
getMethod
(),
(
array
)
$request
->
query
->
getIterator
(),
(
array
)
$request
->
cookies
->
getIterator
(),
(
array
)
$request
->
files
->
getIterator
(),
(
array
)
$request
->
server
->
getIterator
(),
$content
);
$new_request
->
headers
->
set
(
'Content-ID'
,
sprintf
(
'<%s>'
,
$id
));
$new_request
->
attributes
->
set
(
static
::
SUBREQUEST_PARENT_ID
,
$parent_id
);
$new_request
->
attributes
->
set
(
static
::
SUBREQUEST_ID
,
$id
);
$new_request
->
attributes
->
set
(
static
::
SUBREQUEST_TREE
,
$sub_tree
);
$new_request
->
setSession
(
$session
);
return
$new_request
;
}
}
src/Normalizer/JsonBlueprintDenormalizer.php
View file @
970a679e
...
...
@@ -54,10 +54,13 @@ class JsonBlueprintDenormalizer implements DenormalizerInterface, SerializerAwar
// sub-tree to the root.
// TODO: If a tree hangs from a parent that is not attached to the root, then this process may fail.
foreach
(
$requests_per_parent
as
$parent_id
=>
$children_requests
)
{
$parent_request
=
$root_tree
->
getDescendant
(
$parent_id
);
$parent_requests
=
array_filter
(
$requests
,
function
(
Request
$request
)
use
(
$parent_id
)
{
return
$request
->
attributes
->
get
(
RequestTree
::
SUBREQUEST_ID
)
==
$parent_id
;
});
$parent_request
=
reset
(
$parent_requests
);
$parent_request
->
attributes
->
set
(
RequestTree
::
SUBREQUEST_TREE
,
new
RequestTree
(
$children_requests
)
new
RequestTree
(
$children_requests
,
$parent_id
)
);
}
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment