diff --git a/PortableInfobox.setup.php b/PortableInfobox.setup.php index a08dc83..b63720f 100644 --- a/PortableInfobox.setup.php +++ b/PortableInfobox.setup.php @@ -48,6 +48,7 @@ $wgAutoloadClasses[ 'Wikia\PortableInfobox\Helpers\PortableInfoboxDataBag' ] = $ $wgAutoloadClasses[ 'Wikia\PortableInfobox\Helpers\PortableInfoboxRenderServiceHelper' ] = $dir . 'services/Helpers/PortableInfoboxRenderServiceHelper.php'; $wgAutoloadClasses[ 'Wikia\PortableInfobox\Helpers\PortableInfoboxClassification' ] = $dir . 'services/Helpers/PortableInfoboxClassification.php'; $wgAutoloadClasses[ 'Wikia\PortableInfobox\Helpers\PortableInfoboxTemplatesHelper' ] = $dir . 'services/Helpers/PortableInfoboxTemplatesHelper.php'; +$wgAutoloadClasses[ 'Wikia\PortableInfobox\Helpers\PagePropsProxy' ] = $dir . 'services/Helpers/PagePropsProxy.php'; // controller classes $wgAutoloadClasses[ 'PortableInfoboxParserTagController' ] = $dir . 'controllers/PortableInfoboxParserTagController.class.php'; diff --git a/services/Helpers/PagePropsProxy.php b/services/Helpers/PagePropsProxy.php new file mode 100644 index 0000000..ae40924 --- /dev/null +++ b/services/Helpers/PagePropsProxy.php @@ -0,0 +1,15 @@ +getOutput()->getProperty( \PortableInfoboxDataService::INFOBOXES_PROPERTY_NAME ); + return json_decode( $parser->getOutput() + ->getProperty( \PortableInfoboxDataService::INFOBOXES_PROPERTY_NAME ), true ); } } diff --git a/services/PortableInfoboxDataService.class.php b/services/PortableInfoboxDataService.class.php index 68b0b7c..c11707d 100644 --- a/services/PortableInfoboxDataService.class.php +++ b/services/PortableInfoboxDataService.class.php @@ -1,5 +1,6 @@ title = $title; - $this->templateHelper = $helper ? $helper : new PortableInfoboxTemplatesHelper(); - $this->cachekey = wfMemcKey( $title->getArticleID(), self::INFOBOXES_PROPERTY_NAME ); + protected function __construct( $title ) { + $this->title = $title !== null ? $title : new Title(); + $this->templateHelper = new PortableInfoboxTemplatesHelper(); + $this->propsProxy = new PagePropsProxy(); + $this->cachekey = wfMemcKey( $this->title->getArticleID(), self::INFOBOXES_PROPERTY_NAME ); } - public static function newFromTitle( $title, $helper = null ) { - return new PortableInfoboxDataService( $title, $helper ); + public static function newFromTitle( $title ) { + return new PortableInfoboxDataService( $title ); } - public static function newFromPageID( $pageid, $helper = null ) { - return new PortableInfoboxDataService( Title::newFromID( $pageid ), $helper ); + public static function newFromPageID( $pageid ) { + return new PortableInfoboxDataService( Title::newFromID( $pageid ) ); + } + + // set internal helpers methods + public function setTemplatesHelper( $helper ) { + $this->templateHelper = $helper; + + return $this; + } + + public function setPagePropsProxy( $proxy ) { + $this->propsProxy = $proxy; + + return $this; } /** - * Returns infobox data + * Returns infobox data, terminal method * * @return array in format [ 'data' => [], 'sources' => [] ] or [] will be returned */ @@ -44,15 +58,16 @@ class PortableInfoboxDataService { $hidden = $this->templateHelper->parseInfoboxes( $this->title ); if ( $hidden ) { $this->delete(); - $this->set( json_decode( $hidden, true ) ); + $this->set( $hidden ); }; } + $result = $this->get(); - return $this->get(); + return $result !== null ? $result : [ ]; } /** - * Get image list from infobox data + * Get image list from infobox data, terminal method * * @return array */ @@ -79,6 +94,8 @@ class PortableInfoboxDataService { * Save infobox data, permanently * * @param NodeInfobox $raw infobox parser output + * + * @return $this */ public function save( NodeInfobox $raw ) { if ( $raw ) { @@ -86,6 +103,8 @@ class PortableInfoboxDataService { $stored[] = [ 'data' => $raw->getRenderData(), 'sources' => $raw->getSource() ]; $this->set( $stored ); } + + return $this; } /** @@ -94,6 +113,8 @@ class PortableInfoboxDataService { public function delete() { $this->clear(); unset( $this->cache ); + + return $this; } /** @@ -104,6 +125,8 @@ class PortableInfoboxDataService { global $wgMemc; $wgMemc->delete( $this->cachekey ); unset( $this->cache ); + + return $this; } // soft cache handlers @@ -128,7 +151,7 @@ class PortableInfoboxDataService { // first try memcache, then go to props $data = $wgMemc->get( $this->cachekey ); if ( $data === false ) { - $data = json_decode( Wikia::getProps( $id, self::INFOBOXES_PROPERTY_NAME ), true ); + $data = json_decode( $this->propsProxy->get( $id, self::INFOBOXES_PROPERTY_NAME ), true ); $wgMemc->set( $this->cachekey, $data, WikiaResponse::CACHE_STANDARD ); } @@ -143,7 +166,7 @@ class PortableInfoboxDataService { if ( $id ) { global $wgMemc; $wgMemc->set( $this->cachekey, $data, WikiaResponse::CACHE_STANDARD ); - Wikia::setProps( $id, [ self::INFOBOXES_PROPERTY_NAME => json_encode( $data ) ] ); + $this->propsProxy->set( $id, [ self::INFOBOXES_PROPERTY_NAME => json_encode( $data ) ] ); } } @@ -152,7 +175,7 @@ class PortableInfoboxDataService { if ( $id ) { global $wgMemc; $wgMemc->set( $this->cachekey, '', WikiaResponse::CACHE_STANDARD ); - Wikia::setProps( $id, [ self::INFOBOXES_PROPERTY_NAME => '' ] ); + $this->propsProxy->set( $id, [ self::INFOBOXES_PROPERTY_NAME => '' ] ); } } } diff --git a/tests/PortableInfoboxDataServiceTest.php b/tests/PortableInfoboxDataServiceTest.php index 822fa56..b9cc57b 100644 --- a/tests/PortableInfoboxDataServiceTest.php +++ b/tests/PortableInfoboxDataServiceTest.php @@ -1,5 +1,7 @@ [ - [ - "type" => "data", - "data" => [ - "value" => "AAAA", - "label" => "BBBB" - ] - ], - [ - "type" => "image", - "data" => [ - "key" => "Test.jpg", - "alt" => null, - "caption" => null, - ] - ], - [ - "type" => "image", - "data" => [ - "key" => "Test2.jpg", - "alt" => null, - "caption" => null - ] - ] - ] - ], - [ // INFOBOX 2 - 'data' => [ - [ - "type" => "image", - "data" => [ - "key" => "Test2.jpg", - "alt" => null, - "caption" => null - ] - ] - ] - ] - ]; + /** + * @param $id + * @param int $ns + * + * @return Title + */ + protected function prepareTitle( $id = 0, $ns = NS_MAIN ) { + $title = new Title(); + $title->mArticleID = $id; + $title->mNamespace = $ns; - return $data; + return $title; + } + + public function testEmptyData() { + $result = PortableInfoboxDataService::newFromTitle( $this->prepareTitle() ) + // empty page props + ->setPagePropsProxy( new PagePropsProxyDummy( [ ] ) ) + ->getData(); + + $this->assertEquals( [ ], $result ); + } + + public function testLoadFromProps() { + $data = '[{"data": [], "sources": []}]'; + $result = PortableInfoboxDataService::newFromTitle( $this->prepareTitle( 1 ) ) + // purge memc so we can rerun tests + ->purge() + ->setPagePropsProxy( new PagePropsProxyDummy( [ '1infoboxes' => $data ] ) ) + ->getData(); + + $this->assertEquals( json_decode( $data, true ), $result ); + } + + public function testSave() { + $markup = '{{{test2}}}'; + $infoboxNode = NodeFactory::newFromXML( $markup, [ 'test' => 1 ] ); + + $result = PortableInfoboxDataService::newFromTitle( $this->prepareTitle( 1 ) ) + ->purge() + ->setPagePropsProxy( new PagePropsProxyDummy( [ ] ) ) + ->save( $infoboxNode ) + ->getData(); + + $this->assertEquals( [ [ 'data' => [ [ 'type' => 'data', 'data' => [ 'label' => null, 'value' => 1 ] ] ], + 'sources' => [ 'test', 'test2' ] ] ], $result ); + } + + public function testTemplate() { + $data = [ [ 'data' => [ ], 'sources' => [ ] ] ]; + $result = PortableInfoboxDataService::newFromTitle( $this->prepareTitle( 1, NS_TEMPLATE ) ) + ->purge() + ->setPagePropsProxy( new PagePropsProxyDummy( [ ] ) ) + ->setTemplatesHelper( new TemplateHelperDummy( $data ) ) + ->getData(); + + $this->assertEquals( $data, $result ); + } + + public function testDelete() { + $data = '[{"data": [], "sources": []}]'; + $result = PortableInfoboxDataService::newFromTitle( $this->prepareTitle( 1 ) ) + // purge memc so we can rerun tests + ->purge() + ->setPagePropsProxy( new PagePropsProxyDummy( [ '1infoboxes' => $data ] ) ) + ->delete() + ->getData(); + + $this->assertEquals( '', $result ); + } + + public function testPurge() { + $data = '[{"data": [], "sources": []}]'; + $service = PortableInfoboxDataService::newFromTitle( $this->prepareTitle( 1 ) ) + // purge memc so we can rerun tests + ->purge() + ->setPagePropsProxy( new PagePropsProxyDummy( [ '1infoboxes' => $data ] ) ); + + // this should load data from props to memc + $result = $service->getData(); + + $service->purge() + ->setPagePropsProxy( new PagePropsProxyDummy( [ ] ) ); + $purged = $service->getData(); + + $this->assertEquals( [ json_decode( $data, true ), [ ] ], [ $result, $purged ] ); } public function testImageListRemoveDuplicates() { - $mock = $this->getMockBuilder( 'PortableInfoboxDataService' ) - ->disableOriginalConstructor() - ->setMethods( [ 'getData' ] ) - ->getMock(); - $mock->expects( $this->any() )->method( 'getData' )->will( $this->returnValue( $this->getInfoboxData() ) ); + $images = PortableInfoboxDataService::newFromTitle( $this->prepareTitle( 1 ) ) + ->purge() + ->setPagePropsProxy( new PagePropsProxyDummy( [ '1infoboxes' => json_encode( $this->getInfoboxData() ) ] ) ) + ->getImages(); - $images = $mock->getImages(); - $this->assertTrue( count( $images ) === 2 ); + $this->assertEquals( count( $images ), 2 ); } public function testImageListFetchImages() { - $mock = $this->getMockBuilder( 'PortableInfoboxDataService' ) - ->disableOriginalConstructor() - ->setMethods( [ 'getData' ] ) - ->getMock(); - $mock->expects( $this->any() )->method( 'getData' )->will( $this->returnValue( $this->getInfoboxData() ) ); + $images = PortableInfoboxDataService::newFromTitle( $this->prepareTitle( 1 ) ) + ->purge() + ->setPagePropsProxy( new PagePropsProxyDummy( [ '1infoboxes' => json_encode( $this->getInfoboxData() ) ] ) ) + ->getImages(); - $images = $mock->getImages(); - $this->assertTrue( in_array( "Test.jpg", $images ), "Test.jpg should be in images array" ); - $this->assertTrue( in_array( "Test2.jpg", $images ), "Test2.jpg should be in images array" ); + $this->assertEquals( [ 'Test.jpg', 'Test2.jpg' ], $images ); } public function testTitleNullConstructor() { - $service = PortableInfoboxDataService::newFromTitle(null); + $service = PortableInfoboxDataService::newFromTitle( null ); $result = $service->getData(); - $this->assertEquals( [], $result ); + $this->assertEquals( [ ], $result ); } public function testConstructor() { - $service = PortableInfoboxDataService::newFromPageID(null); + $service = PortableInfoboxDataService::newFromPageID( null ); $result = $service->getData(); - $this->assertEquals( [], $result ); + $this->assertEquals( [ ], $result ); } + protected function getInfoboxData() { + return [ [ 'data' => [ [ "type" => "data", + "data" => [ + "value" => "AAAA", + "label" => "BBBB" + ] + ], [ "type" => "image", + "data" => [ + "key" => "Test.jpg", + "alt" => null, + "caption" => null, + ] + ], [ "type" => "image", + "data" => [ + "key" => "Test2.jpg", + "alt" => null, + "caption" => null + ] ] ] ], + [ 'data' => [ [ "type" => "image", + "data" => [ + "key" => "Test2.jpg", + "alt" => null, + "caption" => null + ] ] ] ] ]; + } +} + +class TemplateHelperDummy { + + public function __construct( $hidden = false ) { + $this->hidden = $hidden; + } + + public function parseInfoboxes( $title ) { + return $this->hidden; + } +} + +class PagePropsProxyDummy { + + public function __construct( $data ) { + $this->data = $data; + } + + public function get( $id, $property ) { + $prop = $this->data[ $id . $property ]; + + return $prop !== null ? $prop : ''; + } + + public function set( $id, $data ) { + foreach ( $data as $property => $value ) { + $this->data[ $id . $property ] = $value; + } + } }