2015-04-27 14:05:31 +00:00
|
|
|
<?php
|
|
|
|
namespace Wikia\PortableInfobox\Parser\Nodes;
|
|
|
|
|
|
|
|
use Wikia\PortableInfobox\Parser\ExternalParser;
|
2015-05-07 12:37:13 +00:00
|
|
|
use Wikia\PortableInfobox\Parser\SimpleParser;
|
2015-04-27 14:05:31 +00:00
|
|
|
|
|
|
|
class Node {
|
|
|
|
|
|
|
|
const DATA_SRC_ATTR_NAME = 'source';
|
2015-07-01 15:31:37 +00:00
|
|
|
const DEFAULT_TAG_NAME = 'default';
|
2015-06-22 13:53:01 +00:00
|
|
|
const FORMAT_TAG_NAME = 'format';
|
2015-06-22 15:51:59 +00:00
|
|
|
const LABEL_TAG_NAME = 'label';
|
2015-06-23 12:25:37 +00:00
|
|
|
const EXTRACT_SOURCE_REGEX = '/{{{([^\|}]*?)\|?.*}}}/sU';
|
2015-04-27 14:05:31 +00:00
|
|
|
|
|
|
|
protected $xmlNode;
|
2015-06-11 09:34:28 +00:00
|
|
|
protected $children;
|
2015-06-10 09:28:33 +00:00
|
|
|
protected $data = null;
|
2015-04-27 14:05:31 +00:00
|
|
|
|
2015-06-09 13:09:01 +00:00
|
|
|
/**
|
|
|
|
* @var $externalParser ExternalParser
|
|
|
|
*/
|
2015-04-27 14:05:31 +00:00
|
|
|
protected $externalParser;
|
|
|
|
|
|
|
|
public function __construct( \SimpleXMLElement $xmlNode, $infoboxData ) {
|
|
|
|
$this->xmlNode = $xmlNode;
|
|
|
|
$this->infoboxData = $infoboxData;
|
|
|
|
}
|
|
|
|
|
2015-06-10 09:28:33 +00:00
|
|
|
public function getSource() {
|
2015-06-11 09:48:32 +00:00
|
|
|
return $this->extractSourceFromNode( $this->xmlNode );
|
2015-06-10 09:28:33 +00:00
|
|
|
}
|
|
|
|
|
2016-03-31 09:58:34 +00:00
|
|
|
public function getSourceLabel() {
|
|
|
|
return \Sanitizer::stripAllTags( $this->getInnerValue( $this->xmlNode->{self::LABEL_TAG_NAME} ) );
|
|
|
|
}
|
|
|
|
|
2015-05-07 12:37:13 +00:00
|
|
|
/**
|
|
|
|
* @return ExternalParser
|
|
|
|
*/
|
|
|
|
public function getExternalParser() {
|
|
|
|
if ( !isset( $this->externalParser ) ) {
|
|
|
|
$this->setExternalParser( new SimpleParser() );
|
|
|
|
}
|
2015-06-10 09:28:33 +00:00
|
|
|
|
2015-05-07 12:37:13 +00:00
|
|
|
return $this->externalParser;
|
|
|
|
}
|
|
|
|
|
2015-04-27 14:05:31 +00:00
|
|
|
/**
|
2015-06-10 15:19:40 +00:00
|
|
|
* @param ExternalParser|null $externalParser
|
2015-06-10 09:28:33 +00:00
|
|
|
*
|
|
|
|
* @return $this
|
2015-04-27 14:05:31 +00:00
|
|
|
*/
|
2015-06-10 15:19:40 +00:00
|
|
|
public function setExternalParser( $externalParser ) {
|
|
|
|
// we can pass anything, and ignore it if not ExternalParser instance
|
2015-06-12 13:51:25 +00:00
|
|
|
// we use builder pattern here, for fluently passing external parser to children nodes,
|
|
|
|
// type hinting was removed to prevent catchable fatal error appearing
|
2015-06-10 15:19:40 +00:00
|
|
|
if ( $externalParser instanceof ExternalParser ) {
|
|
|
|
$this->externalParser = $externalParser;
|
|
|
|
}
|
2015-06-10 09:28:33 +00:00
|
|
|
|
|
|
|
return $this;
|
2015-04-27 14:05:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
public function getType() {
|
2015-05-25 13:03:45 +00:00
|
|
|
/*
|
|
|
|
* Node type generation is based on XML tag name.
|
|
|
|
* It's worth to remember that SimpleXMLElement::getName method is
|
|
|
|
* case - sensitive ( "<Data>" != "<data>" ), so we need to sanitize Node Type
|
2015-06-12 13:43:37 +00:00
|
|
|
* by using mb_strtolower function
|
2015-05-25 13:03:45 +00:00
|
|
|
*/
|
2015-06-12 13:43:37 +00:00
|
|
|
return mb_strtolower( $this->xmlNode->getName() );
|
2015-04-27 14:05:31 +00:00
|
|
|
}
|
|
|
|
|
2015-06-11 09:34:28 +00:00
|
|
|
public function isType( $type ) {
|
2015-06-12 13:43:37 +00:00
|
|
|
return strcmp( $this->getType(), mb_strtolower( $type ) ) == 0;
|
2015-06-11 09:34:28 +00:00
|
|
|
}
|
|
|
|
|
2015-04-27 14:05:31 +00:00
|
|
|
public function getData() {
|
2015-06-10 09:28:33 +00:00
|
|
|
if ( !isset( $this->data ) ) {
|
|
|
|
$this->data = [ 'value' => (string)$this->xmlNode ];
|
|
|
|
}
|
|
|
|
|
|
|
|
return $this->data;
|
2015-04-27 14:05:31 +00:00
|
|
|
}
|
|
|
|
|
2015-06-11 09:34:28 +00:00
|
|
|
public function getRenderData() {
|
|
|
|
return [
|
|
|
|
'type' => $this->getType(),
|
|
|
|
'data' => $this->getData(),
|
|
|
|
];
|
|
|
|
}
|
|
|
|
|
2015-05-19 18:14:39 +00:00
|
|
|
/**
|
|
|
|
* @desc Check if node is empty.
|
|
|
|
* Note that a '0' value cannot be treated like a null
|
2015-06-09 08:41:45 +00:00
|
|
|
*
|
|
|
|
* @return bool
|
2015-05-19 18:14:39 +00:00
|
|
|
*/
|
2015-06-10 09:28:33 +00:00
|
|
|
public function isEmpty() {
|
|
|
|
$data = $this->getData()[ 'value' ];
|
|
|
|
|
2015-06-12 13:43:37 +00:00
|
|
|
return ( empty( $data ) && $data != '0' );
|
2015-04-27 14:05:31 +00:00
|
|
|
}
|
|
|
|
|
2015-06-10 15:19:40 +00:00
|
|
|
protected function getChildNodes() {
|
2015-06-11 09:34:28 +00:00
|
|
|
if ( !isset( $this->children ) ) {
|
|
|
|
$this->children = [ ];
|
|
|
|
foreach ( $this->xmlNode as $child ) {
|
2015-09-07 10:22:56 +00:00
|
|
|
$this->children[] = NodeFactory::newFromSimpleXml( $child, $this->infoboxData )
|
2015-06-11 09:34:28 +00:00
|
|
|
->setExternalParser( $this->externalParser );
|
|
|
|
}
|
2015-06-10 15:19:40 +00:00
|
|
|
}
|
|
|
|
|
2015-06-11 09:34:28 +00:00
|
|
|
return $this->children;
|
|
|
|
}
|
|
|
|
|
|
|
|
protected function getDataForChildren() {
|
2015-06-12 13:43:37 +00:00
|
|
|
return array_map(
|
|
|
|
function ( Node $item ) {
|
|
|
|
return [
|
|
|
|
'type' => $item->getType(),
|
|
|
|
'data' => $item->getData(),
|
|
|
|
'isEmpty' => $item->isEmpty(),
|
|
|
|
'source' => $item->getSource()
|
|
|
|
];
|
|
|
|
},
|
|
|
|
$this->getChildNodes()
|
|
|
|
);
|
2015-06-11 09:34:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
protected function getRenderDataForChildren() {
|
|
|
|
return array_map( function ( Node $item ) {
|
|
|
|
return $item->getRenderData();
|
|
|
|
}, array_filter( $this->getChildNodes(), function ( Node $item ) {
|
|
|
|
return !$item->isEmpty();
|
|
|
|
} ) );
|
2015-06-10 15:19:40 +00:00
|
|
|
}
|
|
|
|
|
2015-06-11 09:48:32 +00:00
|
|
|
protected function getSourceForChildren() {
|
|
|
|
/** @var Node $item */
|
|
|
|
$result = [ ];
|
|
|
|
foreach ( $this->getChildNodes() as $item ) {
|
|
|
|
$result = array_merge( $result, $item->getSource() );
|
|
|
|
}
|
2015-08-25 11:00:04 +00:00
|
|
|
$uniqueParams = array_unique( $result );
|
2015-06-11 09:48:32 +00:00
|
|
|
|
2015-08-25 11:00:04 +00:00
|
|
|
return array_values( $uniqueParams );
|
2015-06-11 09:48:32 +00:00
|
|
|
}
|
|
|
|
|
2016-03-31 09:58:34 +00:00
|
|
|
protected function getSourceLabelForChildren() {
|
|
|
|
/** @var Node $item */
|
|
|
|
$result = [ ];
|
|
|
|
foreach ( $this->getChildNodes() as $item ) {
|
|
|
|
$label = $item->getSourceLabel();
|
|
|
|
if ( is_array( $label ) ) {
|
|
|
|
$result = array_merge( $result, $label );
|
|
|
|
} else {
|
|
|
|
$source = $item->getSource()[0];
|
|
|
|
if ( !empty( $source ) && !empty( $source ) ) {
|
|
|
|
$result[$source] = $label;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return $result;
|
|
|
|
}
|
|
|
|
|
2015-04-27 14:05:31 +00:00
|
|
|
protected function getValueWithDefault( \SimpleXMLElement $xmlNode ) {
|
2015-06-08 13:56:08 +00:00
|
|
|
$value = $this->extractDataFromSource( $xmlNode );
|
2015-07-01 15:31:37 +00:00
|
|
|
if ( !$value && $xmlNode->{self::DEFAULT_TAG_NAME} ) {
|
2015-09-07 10:22:56 +00:00
|
|
|
return $this->getInnerValue( $xmlNode->{self::DEFAULT_TAG_NAME} );
|
2015-06-22 15:38:47 +00:00
|
|
|
}
|
2015-09-08 09:29:49 +00:00
|
|
|
if ( ( $value || $value == '0' ) && $xmlNode->{self::FORMAT_TAG_NAME} ) {
|
2015-09-07 10:22:56 +00:00
|
|
|
return $this->getInnerValue( $xmlNode->{self::FORMAT_TAG_NAME} );
|
2015-04-27 14:05:31 +00:00
|
|
|
}
|
2015-06-10 09:28:33 +00:00
|
|
|
|
2015-04-27 14:05:31 +00:00
|
|
|
return $value;
|
|
|
|
}
|
|
|
|
|
2015-05-08 15:57:25 +00:00
|
|
|
protected function getRawValueWithDefault( \SimpleXMLElement $xmlNode ) {
|
2015-06-09 08:41:45 +00:00
|
|
|
$value = $this->getRawInfoboxData( $this->getXmlAttribute( $xmlNode, self::DATA_SRC_ATTR_NAME ) );
|
2015-07-01 15:31:37 +00:00
|
|
|
if ( !$value && $xmlNode->{self::DEFAULT_TAG_NAME} ) {
|
|
|
|
$value = $this->getExternalParser()->replaceVariables( (string)$xmlNode->{self::DEFAULT_TAG_NAME} );
|
2015-05-08 15:57:25 +00:00
|
|
|
}
|
2015-06-10 09:28:33 +00:00
|
|
|
|
2015-05-08 15:57:25 +00:00
|
|
|
return $value;
|
|
|
|
}
|
|
|
|
|
2015-06-08 13:56:08 +00:00
|
|
|
protected function getValueWithData( \SimpleXMLElement $xmlNode ) {
|
|
|
|
$value = $this->extractDataFromSource( $xmlNode );
|
|
|
|
|
2015-06-09 08:41:45 +00:00
|
|
|
return $value ? $value
|
2015-09-07 10:22:56 +00:00
|
|
|
: $this->getInnerValue( $xmlNode );
|
2015-06-08 13:56:08 +00:00
|
|
|
}
|
|
|
|
|
2015-06-11 12:51:54 +00:00
|
|
|
protected function getInnerValue( \SimpleXMLElement $xmlNode ) {
|
2015-09-07 10:22:56 +00:00
|
|
|
return $this->getExternalParser()->parseRecursive( (string)$xmlNode );
|
2015-06-11 12:51:54 +00:00
|
|
|
}
|
|
|
|
|
2015-05-07 12:37:13 +00:00
|
|
|
protected function getXmlAttribute( \SimpleXMLElement $xmlNode, $attribute ) {
|
2015-06-09 08:41:45 +00:00
|
|
|
return ( isset( $xmlNode[ $attribute ] ) ) ? (string)$xmlNode[ $attribute ]
|
|
|
|
: null;
|
2015-04-27 14:05:31 +00:00
|
|
|
}
|
|
|
|
|
2015-06-10 09:28:33 +00:00
|
|
|
protected function getRawInfoboxData( $key ) {
|
2015-06-09 08:41:45 +00:00
|
|
|
return isset( $this->infoboxData[ $key ] ) ? $this->infoboxData[ $key ]
|
|
|
|
: null;
|
2015-05-08 15:57:25 +00:00
|
|
|
}
|
|
|
|
|
2015-04-27 14:05:31 +00:00
|
|
|
protected function getInfoboxData( $key ) {
|
2015-06-10 09:28:33 +00:00
|
|
|
return $this->getExternalParser()->parseRecursive( $this->getRawInfoboxData( $key ) );
|
2015-04-27 14:05:31 +00:00
|
|
|
}
|
2015-06-11 09:48:32 +00:00
|
|
|
|
2015-06-08 13:56:08 +00:00
|
|
|
/**
|
|
|
|
* @param \SimpleXMLElement $xmlNode
|
|
|
|
*
|
|
|
|
* @return mixed
|
|
|
|
*/
|
|
|
|
protected function extractDataFromSource( \SimpleXMLElement $xmlNode ) {
|
|
|
|
$source = $this->getXmlAttribute( $xmlNode, self::DATA_SRC_ATTR_NAME );
|
|
|
|
|
2016-01-04 13:34:10 +00:00
|
|
|
return ( !empty( $source ) || $source == '0' ) ? $this->getInfoboxData( $source )
|
2015-06-09 08:41:45 +00:00
|
|
|
: null;
|
2015-06-08 13:56:08 +00:00
|
|
|
}
|
|
|
|
|
2015-06-11 09:48:32 +00:00
|
|
|
/**
|
|
|
|
* @param \SimpleXMLElement $xmlNode
|
|
|
|
*
|
|
|
|
* @return array
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
protected function extractSourceFromNode( \SimpleXMLElement $xmlNode ) {
|
2015-09-07 10:22:56 +00:00
|
|
|
$source = $this->getXmlAttribute( $xmlNode, self::DATA_SRC_ATTR_NAME ) ? [ $this->getXmlAttribute( $xmlNode, self::DATA_SRC_ATTR_NAME ) ] : [ ];
|
2015-06-23 11:05:25 +00:00
|
|
|
|
|
|
|
if ( $xmlNode->{self::FORMAT_TAG_NAME} ) {
|
2015-06-23 12:25:37 +00:00
|
|
|
$source = $this->matchVariables( $xmlNode->{self::FORMAT_TAG_NAME}, $source );
|
2015-06-23 11:05:25 +00:00
|
|
|
}
|
2015-07-01 15:31:37 +00:00
|
|
|
if ( $xmlNode->{self::DEFAULT_TAG_NAME} ) {
|
|
|
|
$source = $this->matchVariables( $xmlNode->{self::DEFAULT_TAG_NAME}, $source );
|
2015-06-11 09:48:32 +00:00
|
|
|
}
|
|
|
|
|
2015-06-23 11:05:25 +00:00
|
|
|
return $source;
|
2015-06-11 09:48:32 +00:00
|
|
|
}
|
2015-06-23 12:25:37 +00:00
|
|
|
|
|
|
|
protected function matchVariables( \SimpleXMLElement $node, array $source ) {
|
|
|
|
preg_match_all( self::EXTRACT_SOURCE_REGEX, (string)$node, $sources );
|
2015-09-07 10:22:56 +00:00
|
|
|
|
|
|
|
return array_unique( array_merge( $source, $sources[ 1 ] ) );
|
2015-06-23 12:25:37 +00:00
|
|
|
}
|
2015-04-27 14:05:31 +00:00
|
|
|
}
|