class FeedsExJmesPath in Feeds extensible parsers 7
Same name and namespace in other branches
- 7.2 src/FeedsExJmesPath.inc \FeedsExJmesPath
Parses JSON documents with JMESPath.
Hierarchy
- class \FeedsExBase extends \FeedsParser
- class \FeedsExJmesPath
Expanded class hierarchy of FeedsExJmesPath
2 string references to 'FeedsExJmesPath'
- FeedsExJmesPath.test in src/
Tests/ FeedsExJmesPath.test - feeds_ex_feeds_plugins in ./
feeds_ex.feeds.inc - Implements hook_feeds_plugins().
File
- src/
FeedsExJmesPath.inc, line 22 - Contains FeedsExJmesPath.
View source
class FeedsExJmesPath extends FeedsExBase {
/**
* The JMESPath parser.
*
* This is an object with an __invoke() method.
*
* @var object
*
* @todo add interface so checking for an object with an __invoke() method
* becomes explicit?
*/
protected $runtime;
/**
* Returns the compilation directory.
*
* @return string
* The directory JmesPath uses to store generated code.
*/
protected function getCompileDirectory() {
// Look for a previous directory.
$directory = variable_get('feeds_ex_jmespath_compile_dir');
// The temp directory doesn't exist, or has moved.
if (!$this
->validateCompileDirectory($directory)) {
$directory = $this
->generateCompileDirectory();
variable_set('feeds_ex_jmespath_compile_dir', $directory);
// Creates the directory with the correct perms. We don't check the
// return value since if it didn't work, there's nothing we can do. We
// just fallback to the AstRuntime anyway.
$this
->validateCompileDirectory($directory);
}
return $directory;
}
/**
* Generates a directory path to store auto-generated PHP files.
*
* @return string
* A temp directory path.
*/
protected function generateCompileDirectory() {
// A random prefix to store the generated files.
$prefix = drupal_base64_encode(drupal_random_bytes(40));
return file_directory_temp() . '/' . $prefix . '_feeds_ex_jmespath_dir';
}
/**
* Validates that a compile directory exists and is valid.
*
* @param string $directory
* A directory path.
*
* @return bool
* True if the directory exists and is writable, false if not.
*/
protected function validateCompileDirectory($directory) {
if (!$directory) {
return FALSE;
}
return file_prepare_directory($directory, FILE_CREATE_DIRECTORY | FILE_MODIFY_PERMISSIONS);
}
/**
* Returns data from the input array that matches a JMESPath expression.
*
* @param string $expression
* JMESPath expression to evaluate.
* @param mixed $data
* JSON-like data to search.
*
* @return mixed|null
* Returns the matching data or null.
*/
protected function search($expression, $data) {
if (!isset($this->runtime)) {
$this->runtime = $this
->createRuntime($this
->getCompileDirectory());
}
// Stupid PHP.
$runtime = $this->runtime;
return $runtime($expression, $data);
}
/**
* Creates a runtime object.
*
* Checks for different versions of JMESPath.php.
*
* @param string $directory
* The compile directory.
*
* @return object
* An invokable runtime object.
*/
protected function createRuntime($directory) {
// Version 2.
if (class_exists('JmesPath\\AstRuntime')) {
try {
$runtime = new CompilerRuntime2($directory);
} catch (RuntimeException $e) {
$runtime = new AstRuntime2();
}
}
elseif (class_exists('JmesPath\\Runtime\\AstRuntime')) {
try {
$runtime = new CompilerRuntime1(array(
'dir' => $directory,
));
} catch (RuntimeException $e) {
$runtime = new AstRuntime1();
}
$runtime = new FeedsExJmesPathV1Wrapper($runtime);
}
else {
throw new RuntimeException(t('JMESPath.php is not installed correctly.'));
}
return $runtime;
}
/**
* {@inheritdoc}
*/
protected function executeContext(FeedsSource $source, FeedsFetcherResult $fetcher_result) {
$parsed = FeedsExJsonUtility::decodeJsonObject($this
->prepareRaw($fetcher_result));
$parsed = $this
->search($this->config['context']['value'], $parsed);
if (!is_array($parsed) && !is_object($parsed)) {
throw new RuntimeException(t('The context expression must return an object or array.'));
}
// If an object is returned, consider it one item.
if (is_object($parsed)) {
return array(
$parsed,
);
}
$state = $source
->state(FEEDS_PARSE);
if (!$state->total) {
$state->total = count($parsed);
}
$start = (int) $state->pointer;
$state->pointer = $start + $source->importer
->getLimit();
return array_slice($parsed, $start, $source->importer
->getLimit());
}
/**
* {@inheritdoc}
*/
protected function cleanUp(FeedsSource $source, FeedsParserResult $result) {
// @todo Verify if this is necessary. Not sure if the runtime keeps a
// reference to the input data.
unset($this->runtime);
// Calculate progress.
$state = $source
->state(FEEDS_PARSE);
$state
->progress($state->total, $state->pointer);
}
/**
* {@inheritdoc}
*/
protected function executeSourceExpression($machine_name, $expression, $row) {
try {
$result = $this
->search($expression, $row);
} catch (Exception $e) {
// There was an error executing this expression, nothing we can do about
// it.
return;
}
if (is_object($result)) {
$result = (array) $result;
}
if (!is_array($result)) {
return $result;
}
$count = count($result);
if ($count === 0) {
return;
}
return count($result) === 1 ? reset($result) : array_values($result);
}
/**
* {@inheritdoc}
*/
protected function validateExpression(&$expression) {
$expression = trim($expression);
if (!strlen($expression)) {
return;
}
try {
$this
->search($expression, array());
} catch (SyntaxErrorException $e) {
// Remove newlines after nl2br() to make testing easier.
return str_replace("\n", '', nl2br(check_plain(trim($e
->getMessage()))));
} catch (Exception $e) {
// This is a problem executing the query, which we don't worry about.
}
}
/**
* {@inheritdoc}
*/
protected function startErrorHandling() {
// Clear the json errors from previous parsing.
json_decode('{}');
}
/**
* {@inheritdoc}
*/
protected function getErrors() {
if (!function_exists('json_last_error')) {
return array();
}
if (!($error = json_last_error())) {
return array();
}
$message = array(
'message' => FeedsExJsonUtility::translateError($error),
'variables' => array(),
'severity' => WATCHDOG_ERROR,
);
return array(
$message,
);
}
/**
* {@inheritdoc}
*/
protected function loadLibrary() {
if (!FeedsExJsonUtility::jmesPathParserInstalled()) {
throw new RuntimeException(t('The JMESPath library is not installed.'));
}
}
}
Members
Name | Modifiers | Type | Description | Overrides |
---|---|---|---|---|
FeedsExBase:: |
protected | property | The encoder used to convert encodings. | |
FeedsExBase:: |
protected | property | The class used as the text encoder. | 1 |
FeedsExBase:: |
protected | property | The object used to display messages to the user. | |
FeedsExBase:: |
public | function | 1 | |
FeedsExBase:: |
public | function | 1 | |
FeedsExBase:: |
protected | function | Returns a form element for a specific column. | 1 |
FeedsExBase:: |
protected | function | Reuturns the list of table headers. | 1 |
FeedsExBase:: |
public | function | 1 | |
FeedsExBase:: |
protected | function | Renders our debug messages into a list. | |
FeedsExBase:: |
protected | function | Executes the source expressions. | |
FeedsExBase:: |
public | function | Returns the encoder. | |
FeedsExBase:: |
protected | function | Returns the configuration form table header. | |
FeedsExBase:: |
public | function | ||
FeedsExBase:: |
public | function | Returns the messenger. | |
FeedsExBase:: |
public | function | ||
FeedsExBase:: |
protected | function | Returns whether or not this parser uses a context query. | 2 |
FeedsExBase:: |
public | function | ||
FeedsExBase:: |
protected | function | Logs errors. | |
FeedsExBase:: |
public | function | ||
FeedsExBase:: |
protected | function | Performs the actual parsing. | 2 |
FeedsExBase:: |
protected | function | Prepares the expressions for parsing. | |
FeedsExBase:: |
protected | function | Prepares the raw string for parsing. | |
FeedsExBase:: |
protected | function | Prepares the variable map used to substitution. | |
FeedsExBase:: |
protected | function | Prints errors to the screen. | |
FeedsExBase:: |
public | function | Sets the encoder. | |
FeedsExBase:: |
public | function | Sets the messenger to be used to display messages. | |
FeedsExBase:: |
protected | function | Allows subclasses to prepare for parsing. | 3 |
FeedsExBase:: |
public | function | ||
FeedsExBase:: |
public | function | ||
FeedsExBase:: |
public | function | ||
FeedsExBase:: |
public | function | ||
FeedsExBase:: |
protected | function | Stops internal error handling. | 1 |
FeedsExJmesPath:: |
protected | property | The JMESPath parser. | |
FeedsExJmesPath:: |
protected | function |
Allows subclasses to cleanup after parsing. Overrides FeedsExBase:: |
1 |
FeedsExJmesPath:: |
protected | function | Creates a runtime object. | |
FeedsExJmesPath:: |
protected | function |
Returns rows to be parsed. Overrides FeedsExBase:: |
|
FeedsExJmesPath:: |
protected | function |
Executes a single source expression. Overrides FeedsExBase:: |
|
FeedsExJmesPath:: |
protected | function | Generates a directory path to store auto-generated PHP files. | |
FeedsExJmesPath:: |
protected | function | Returns the compilation directory. | |
FeedsExJmesPath:: |
protected | function |
Returns the errors after parsing. Overrides FeedsExBase:: |
|
FeedsExJmesPath:: |
protected | function |
Loads the necessary library. Overrides FeedsExBase:: |
|
FeedsExJmesPath:: |
protected | function | Returns data from the input array that matches a JMESPath expression. | |
FeedsExJmesPath:: |
protected | function |
Starts internal error handling. Overrides FeedsExBase:: |
|
FeedsExJmesPath:: |
protected | function | Validates that a compile directory exists and is valid. | |
FeedsExJmesPath:: |
protected | function |
Validates an expression. Overrides FeedsExBase:: |