Page Menu
Home
WickedGov Phorge
Search
Configure Global Search
Log In
Files
F2754184
Dispatcher.php
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Flag For Later
Award Token
Size
6 KB
Referenced Files
None
Subscribers
None
Dispatcher.php
View Options
<?php
declare
(
strict_types
=
1
);
namespace
AdvancedJsonRpc
;
use
JsonMapper
;
use
JsonMapper_Exception
;
use
phpDocumentor\Reflection\DocBlockFactory
;
use
phpDocumentor\Reflection\Types
;
use
ReflectionException
;
use
ReflectionMethod
;
use
ReflectionNamedType
;
class
Dispatcher
{
/**
* @var object
*/
private
$target
;
/**
* @var string
*/
private
$delimiter
;
/**
* method => ReflectionMethod[]
*
* @var ReflectionMethod
*/
private
$methods
;
/**
* @var \phpDocumentor\Reflection\DocBlockFactory
*/
private
$docBlockFactory
;
/**
* @var \phpDocumentor\Reflection\Types\ContextFactory
*/
private
$contextFactory
;
/**
* @param object $target The target object that should receive the method calls
* @param string $delimiter A delimiter for method calls on properties, for example someProperty->someMethod
*/
public
function
__construct
(
$target
,
$delimiter
=
'->'
)
{
$this
->
target
=
$target
;
$this
->
delimiter
=
$delimiter
;
$this
->
docBlockFactory
=
DocBlockFactory
::
createInstance
();
$this
->
contextFactory
=
new
Types\ContextFactory
();
$this
->
mapper
=
new
JsonMapper
();
}
/**
* Calls the appropriate method handler for an incoming Message
*
* @param string|object $msg The incoming message
* @return mixed
*/
public
function
dispatch
(
$msg
)
{
if
(
is_string
(
$msg
))
{
$msg
=
json_decode
(
$msg
);
if
(
json_last_error
()
!==
JSON_ERROR_NONE
)
{
throw
new
Error
(
json_last_error_msg
(),
ErrorCode
::
PARSE_ERROR
);
}
}
// Find out the object and function that should be called
$obj
=
$this
->
target
;
$parts
=
explode
(
$this
->
delimiter
,
$msg
->
method
);
// The function to call is always the last part of the method
$fn
=
array_pop
(
$parts
);
// For namespaced methods like textDocument/didOpen, call the didOpen method on the $textDocument property
// For simple methods like initialize, shutdown, exit, this loop will simply not be entered and $obj will be
// the target
foreach
(
$parts
as
$part
)
{
if
(!
isset
(
$obj
->
$part
))
{
throw
new
Error
(
"Method {$msg->method} is not implemented"
,
ErrorCode
::
METHOD_NOT_FOUND
);
}
$obj
=
$obj
->
$part
;
}
if
(!
isset
(
$this
->
methods
[
$msg
->
method
]))
{
try
{
$method
=
new
ReflectionMethod
(
$obj
,
$fn
);
$this
->
methods
[
$msg
->
method
]
=
$method
;
}
catch
(
ReflectionException
$e
)
{
throw
new
Error
(
$e
->
getMessage
(),
ErrorCode
::
METHOD_NOT_FOUND
,
null
,
$e
);
}
}
$method
=
$this
->
methods
[
$msg
->
method
];
$parameters
=
$method
->
getParameters
();
if
(
$method
->
getDocComment
())
{
$docBlock
=
$this
->
docBlockFactory
->
create
(
$method
->
getDocComment
(),
$this
->
contextFactory
->
createFromReflector
(
$method
->
getDeclaringClass
())
);
$paramTags
=
$docBlock
->
getTagsByName
(
'param'
);
}
$args
=
[];
if
(
isset
(
$msg
->
params
))
{
// Find out the position
if
(
is_array
(
$msg
->
params
))
{
$args
=
$msg
->
params
;
}
else
if
(
is_object
(
$msg
->
params
))
{
foreach
(
$parameters
as
$pos
=>
$parameter
)
{
$value
=
null
;
foreach
(
get_object_vars
(
$msg
->
params
)
as
$key
=>
$val
)
{
if
(
$parameter
->
name
===
$key
)
{
$value
=
$val
;
break
;
}
}
$args
[
$pos
]
=
$value
;
}
}
else
{
throw
new
Error
(
'Params must be structured or omitted'
,
ErrorCode
::
INVALID_REQUEST
);
}
foreach
(
$args
as
$position
=>
$value
)
{
try
{
// If the type is structured (array or object), map it with JsonMapper
if
(
is_object
(
$value
))
{
// Does the parameter have a type hint?
$param
=
$parameters
[
$position
];
if
(
$param
->
hasType
())
{
$paramType
=
$param
->
getType
();
if
(
$paramType
instanceof
ReflectionNamedType
)
{
// We have object data to map and want the class name.
// This should not include the `?` if the type was nullable.
$class
=
$paramType
->
getName
();
}
else
{
// Fallback for php 7.0, which is still supported (and doesn't have nullable).
$class
=
(
string
)
$paramType
;
}
$value
=
$this
->
mapper
->
map
(
$value
,
new
$class
());
}
}
else
if
(
is_array
(
$value
)
&&
isset
(
$docBlock
))
{
// Get the array type from the DocBlock
$type
=
$paramTags
[
$position
]->
getType
();
// For union types, use the first one that is a class array (often it is SomeClass[]|null)
if
(
$type
instanceof
Types\Compound
)
{
for
(
$i
=
0
;
$t
=
$type
->
get
(
$i
);
$i
++)
{
if
(
$t
instanceof
Types\Array_
&&
$t
->
getValueType
()
instanceof
Types\Object_
&&
(
string
)
$t
->
getValueType
()
!==
'object'
)
{
$class
=
(
string
)
$t
->
getValueType
()->
getFqsen
();
$value
=
$this
->
mapper
->
mapArray
(
$value
,
[],
$class
);
break
;
}
}
}
else
if
(
$type
instanceof
Types\Array_
)
{
$class
=
(
string
)
$type
->
getValueType
()->
getFqsen
();
$value
=
$this
->
mapper
->
mapArray
(
$value
,
[],
$class
);
}
else
{
throw
new
Error
(
'Type is not matching @param tag'
,
ErrorCode
::
INVALID_PARAMS
);
}
}
}
catch
(
JsonMapper_Exception
$e
)
{
throw
new
Error
(
$e
->
getMessage
(),
ErrorCode
::
INVALID_PARAMS
,
null
,
$e
);
}
$args
[
$position
]
=
$value
;
}
}
ksort
(
$args
);
$result
=
$obj
->
$fn
(...
$args
);
return
$result
;
}
}
File Metadata
Details
Attached
Mime Type
text/x-php
Expires
Fri, Jul 3, 22:16 (1 h, 10 m)
Storage Engine
local-disk
Storage Format
Raw Data
Storage Handle
1e/8a/762b7b6ee7e5b0cb5f92a53458e8
Default Alt Text
Dispatcher.php (6 KB)
Attached To
Mode
rMWPROD MediaWiki Production
Attached
Detach File
Event Timeline
Log In to Comment