PortableInfobox/includes/services/PortableInfoboxDataService.class.php

239 lines
5.8 KiB
PHP
Raw Normal View History

2015-06-09 10:14:00 +00:00
<?php
use PortableInfobox\Helpers\PagePropsProxy;
use PortableInfobox\Helpers\PortableInfoboxParsingHelper;
use PortableInfobox\Parser\Nodes\NodeInfobox;
2015-06-09 10:14:00 +00:00
class PortableInfoboxDataService {
2018-08-08 08:29:34 +00:00
const CACHE_TTL = 86400; // 24 hours
2015-06-09 10:14:00 +00:00
const IMAGE_FIELD_TYPE = 'image';
const INFOBOXES_PROPERTY_NAME = 'infoboxes';
2015-06-09 10:14:00 +00:00
protected $title;
protected $parsingHelper;
2015-09-23 13:51:41 +00:00
protected $propsProxy;
protected $cache;
protected $memcached;
protected $cachekey;
/**
* @param $title Title
2015-09-23 13:51:41 +00:00
*
* @internal param $helper
*/
2015-09-23 13:51:41 +00:00
protected function __construct( $title ) {
$this->title = $title !== null ? $title : new Title();
$this->parsingHelper = new PortableInfoboxParsingHelper();
2015-09-23 13:51:41 +00:00
$this->propsProxy = new PagePropsProxy();
$this->memcached = ObjectCache::getMainWANInstance();
$this->cachekey = $this->memcached->makeKey(
__CLASS__,
$this->title->getArticleID(),
self::INFOBOXES_PROPERTY_NAME,
PortableInfoboxParserTagController::PARSER_TAG_VERSION
);
}
2015-09-23 13:51:41 +00:00
public static function newFromTitle( $title ) {
return new PortableInfoboxDataService( $title );
}
2015-09-23 13:51:41 +00:00
public static function newFromPageID( $pageid ) {
return new PortableInfoboxDataService( Title::newFromID( $pageid ) );
}
// set internal helpers methods
public function setParsingHelper( $helper ) {
$this->parsingHelper = $helper;
2015-09-23 13:51:41 +00:00
return $this;
}
public function setPagePropsProxy( $proxy ) {
$this->propsProxy = $proxy;
return $this;
}
/**
2015-09-24 14:25:27 +00:00
* Returns infobox data, chain terminator method
*
2016-12-09 14:56:57 +00:00
* @return array in format [ [ 'data' => [], 'metadata' => [] ] or [] will be returned
*/
public function getData() {
if ( $this->title && $this->title->exists() && $this->title->inNamespace( NS_TEMPLATE ) ) {
$incOnlyTemplates = $this->parsingHelper->parseIncludeonlyInfoboxes( $this->title );
2018-08-02 16:05:29 +00:00
$this->delete();
$this->set( $incOnlyTemplates );
2015-06-09 10:14:00 +00:00
}
2015-09-23 13:51:41 +00:00
$result = $this->get();
2015-09-23 13:51:41 +00:00
return $result !== null ? $result : [ ];
2015-06-09 10:14:00 +00:00
}
/**
* @return array of strings (infobox markups)
*/
public function getInfoboxes() {
return $this->parsingHelper->getMarkup( $this->title );
}
2015-06-09 12:31:04 +00:00
/**
* Get image list from multiple infoboxes data
*
2015-06-09 12:31:04 +00:00
* @return array
*/
public function getImages() {
$images = [ ];
foreach ( $this->getData() as $infobox ) {
if ( is_array( $infobox[ 'data' ] ) ) {
$images = array_merge( $images, $this->getImageFromOneInfoboxData( $infobox[ 'data' ] ) );
}
}
return array_unique( $images );
}
/**
* Get image list from single infobox data
*
* @return array
*/
private function getImageFromOneInfoboxData( $infoboxData ) {
$images = [ ];
foreach ( $infoboxData as $infoboxDataField ) {
if ( $infoboxDataField[ 'type' ] === self::IMAGE_FIELD_TYPE && isset( $infoboxDataField[ 'data' ] ) ) {
$images = array_merge( $images, $this->getImagesFromOneNodeImageData( $infoboxDataField[ 'data' ] ) );
2015-06-09 10:14:00 +00:00
}
}
return $images;
}
/**
* Get image list from single NodeImage data
*
* @return array
*/
private function getImagesFromOneNodeImageData( $nodeImageData ) {
$images = [ ];
for ( $i = 0; $i < count( $nodeImageData ); $i++ ) {
if ( !empty( $nodeImageData[ $i ] [ 'key' ] ) ) {
$images[] = $nodeImageData[ $i ][ 'key' ];
}
}
return $images;
2015-06-09 10:14:00 +00:00
}
2015-08-19 20:00:27 +00:00
/**
* Save infobox data, permanently
* NOTICE: This method isn't currently used anywhere
*
* @param NodeInfobox $raw infobox parser output
2015-09-23 13:51:41 +00:00
*
* @return $this
2015-08-19 20:00:27 +00:00
*/
public function save( NodeInfobox $raw ) {
if ( $raw ) {
$stored = $this->get();
$stored[] = [
2016-12-14 12:54:53 +00:00
'parser_tag_version' => PortableInfoboxParserTagController::PARSER_TAG_VERSION,
'data' => $raw->getRenderData(),
'metadata' => $raw->getMetadata()
];
$this->set( $stored );
2015-08-19 20:00:27 +00:00
}
2015-09-23 13:51:41 +00:00
return $this;
2015-08-19 20:00:27 +00:00
}
/**
* Remove infobox data from page props and memcache
2015-08-19 20:00:27 +00:00
*/
public function delete() {
$this->clear();
unset( $this->cache );
2015-09-23 13:51:41 +00:00
return $this;
2015-08-19 20:00:27 +00:00
}
2015-08-20 13:52:36 +00:00
/**
* Purge mem cache and local cache
2015-08-20 13:52:36 +00:00
*/
public function purge() {
$this->memcached->delete( $this->cachekey );
unset( $this->cache );
2015-09-23 13:51:41 +00:00
return $this;
}
2015-08-20 13:52:36 +00:00
// soft cache handlers
protected function get() {
if ( !isset( $this->cache ) ) {
$this->cache = $this->load();
2015-08-25 12:27:01 +00:00
}
return $this->cache;
}
2015-08-25 12:27:01 +00:00
protected function set( $data ) {
$this->store( $data );
$this->cache = $data;
2015-08-25 12:27:01 +00:00
}
// PageProps handlers with memcache wrappers
protected function load() {
$id = $this->title->getArticleID();
if ( $id ) {
2018-08-08 08:29:34 +00:00
return $this->memcached->getWithSetCallback( $this->cachekey, self::CACHE_TTL, function () use ( $id ) {
return $this->reparseArticleIfNeeded(
json_decode( $this->propsProxy->get( $id, self::INFOBOXES_PROPERTY_NAME ), true )
);
2015-09-24 14:25:27 +00:00
} );
}
2015-08-25 12:27:01 +00:00
return [ ];
}
/**
* If PageProps has an old version of infobox data/metadata then reparse the page and store fresh data
* If it doesn't have infoboxes property, we treat it as a page without infoboxes - there might be false negatives
*
* @param $infoboxes
*
* @return array
*/
protected function reparseArticleIfNeeded( $infoboxes ) {
if ( is_array( $infoboxes ) ) {
foreach ( $infoboxes as $infobox ) {
if (
empty( $infobox ) ||
!isset( $infobox[ 'parser_tag_version' ] ) ||
$infobox[ 'parser_tag_version' ] !== PortableInfoboxParserTagController::PARSER_TAG_VERSION
) {
$infoboxes = $this->parsingHelper->reparseArticle( $this->title );
$this->set( $infoboxes );
}
}
}
return $infoboxes;
}
protected function store( $data ) {
$id = $this->title->getArticleID();
if ( $id ) {
2018-08-08 08:29:34 +00:00
$this->memcached->set( $this->cachekey, $data, self::CACHE_TTL );
2015-09-23 13:51:41 +00:00
$this->propsProxy->set( $id, [ self::INFOBOXES_PROPERTY_NAME => json_encode( $data ) ] );
}
}
protected function clear() {
$id = $this->title->getArticleID();
if ( $id ) {
2015-09-23 13:51:41 +00:00
$this->propsProxy->set( $id, [ self::INFOBOXES_PROPERTY_NAME => '' ] );
// don't cache clear state
$this->purge();
}
2015-08-20 13:52:36 +00:00
}
2015-06-09 10:14:00 +00:00
}