diff --git a/include/mw/API.php b/include/mw/API.php index b6abca1..0542911 100644 --- a/include/mw/API.php +++ b/include/mw/API.php @@ -1,353 +1,353 @@ . # MediaWiki namespace mw; use cli\Log; /** * Make HTTP request to a MediaWiki API */ class API extends \network\HTTPRequest { /** * MediaWiki tokens handler * * @var mw\Tokens */ private $tokens; /** * Default MediaWiki login username * * @var string */ static $DEFAULT_USERNAME; /** * Default MediaWiki login password * * @var string */ static $DEFAULT_PASSWORD; /** * Default MediaWiki API maxlag * * See https://www.mediawiki.org/wiki/Manual:Maxlag_parameter * * @var int */ static $DEFAULT_MAXLAG = 5; /** * Default MediaWiki API response format * * @var string */ static $DEFAULT_FORMAT = 'json'; /** * Inspect POST flag * * @var bool */ public static $INSPECT_BEFORE_POST = false; /** * Username used for the login. * * @var string */ private $username; /** * Constructor * * @param $api string API endpoint */ public function __construct( $api ) { parent::__construct( $api, [] ); $this->tokens = new Tokens( $this ); } /** * Create an API query with continuation handler * * @param $data array Data * @return mw\APIQuery */ public function createQuery( $data ) { return new APIQuery( $this, $data ); } /** * Effectuate an HTTP POST request but only after a login. * * @param $data array GET/POST data * @param $args array Internal arguments * @override \network\HTTPRequest#post() * @return mixed */ public function post( $data = [], $args = [] ) { if( !$this->isLogged() ) { $this->login(); } if( static::$INSPECT_BEFORE_POST ) { print_r( $data ); \cli\Input::askInput( "Press ENTER to submit" ); } return parent::post( $data, $args ); } /** * Effectuate an HTTP POST (multipart) request but only after a login. * * @param $data array Array of ContentDispositions(s) * @param $args array Internal arguments * @override \network\HTTPRequest#post() * @return mixed */ public function postMultipart( $data = [], $args = [] ) { if( !$this->isLogged() ) { $this->login(); } if( static::$INSPECT_BEFORE_POST ) { print_r( $data ); \cli\Input::askInput( "Press ENTER to submit" ); } return parent::postMultipart( $data, $args ); } /** * Fetch response * * @param $data array GET/POST data * @return mixed */ public function fetch( $data = [], $args = [] ) { if( [] === $data ) { throw \InvalidArgumentException( 'empty data' ); } return parent::fetch( $data, $args ); } /** * Preload some tokens * * @return self */ public function preloadTokens( $tokens ) { $this->tokens->preload( $tokens ); return $this; } /** * Get the value of a token * * @param $token string Token name * @return string Token value */ public function getToken( $token ) { return $this->tokens->get( $token ); } /** * Invalidate a token * * @param $token string Token name * @return self */ public function invalidateToken( $token ) { $this->tokens->invalidate( $token ); return $this; } /** * Get the username used for the login * * @return string|null */ public function getUsername() { return $this->username; } /** * Check if it's already logged in. * * @return bool */ public function isLogged() { return $this->getUsername() !== null; } /** * Login into MediaWiki using an username/password pair. * * Yes, I'm talking about a bot password. * * @param string $username Username * @param string $password Password * @return self */ public function login( $username = null, $password = null ) { // Can use a default set of credentials if( ! $username && ! $password ) { if( $this->isLogged() ) { return $this; } $username = self::$DEFAULT_USERNAME; $password = self::$DEFAULT_PASSWORD; } // no password no party if( !$username || !$password ) { throw new \Exception( sprintf( 'you must call %1$s#login( $username, $password ) or '. 'set %1$s::$DEFAULT_USERNAME and %1$s::$DEFAULT_PASSWORD ' . 'before trying to login', - __CLASS__ + self::class ) ); } // keep track of the login Log::info( "login with username '$username'" ); // Login $response = parent::post( [ 'action' => 'login', 'lgname' => $username, 'lgpassword' => $password, 'lgtoken' => $this->getToken( Tokens::LOGIN ), ], [ // do not show this sensitive data in cleartext in the log 'sensitive' => true, ] ); // no success no party // TODO: create ExceptionLoginFailed and pass $response to it if( !isset( $response->login->result ) || $response->login->result !== 'Success' ) { print_r( $response ); throw new \Exception("login failed"); } // remember the username $this->username = $response->login->lgusername; return $this; } /** * Filters the data before using it. * * Array elements are imploded by a pipe * NULL values are unset * * @override network\HTTPRequest::onDataReady() * @param $data array GET/POST data * @return array */ protected function onDataReady( $data ) { // Some default values $data = array_replace( [ 'maxlag' => self::$DEFAULT_MAXLAG, 'format' => self::$DEFAULT_FORMAT, ], $data ); foreach( $data as $k => $v ) { if( null === $v ) { unset( $data[ $k ] ); } elseif( is_array( $v ) ) { // remove duplicates (API netiquette) $v = array_unique( $v ); // index alphabetically (API netiquette) sort( $v, SORT_STRING ); $data[ $k ] = implode( '|', $v ); } } if( $this->isLogged() ) { $data = array_replace( [ 'assertuser' => $this->getUsername(), ], $data ); } return $data; } /** * JSON decode and check formal API errors * * @param $response mixed Response * @param $request_data array GET/POST request data * @param $method string HTTP Method 'GET'/'POST' * @override \network\HTTPRequest#onFetched() * @throws \mw\API\Exception */ protected function onFetched( $response_raw, $request_data, $method ) { $response = json_decode( $response_raw ); if( null === $response ) { Log::debug( $response_raw ); throw new \Exception( 'response is not JSON-encoded' ); } // print warnings $warnings = $response->warnings ?? []; foreach( $warnings as $subject => $warning ) { Log::warn( sprintf( '%s: %s', $subject, $warning->{'*'} ) ); } if( isset( $response->error ) ) { // print messages $messages = $response->error->messages ?? []; foreach( $messages as $message ) { Log::warn( sprintf( '%s: %s', $message->name, $message->html->{'*'} ) ); foreach( $message->parameters ?? [] as $message_parameter ) { Log::warn( " $message_parameter" ); } } $exception = API\Exception::createFromApiError( $response->error ); if( $exception instanceof API\MaxLagException ) { // retry after some time when server lags Log::warn( "Lag! ({$this->api}) {$response->error->info}" ); $args = [ 'wait-anti-dos' => true, ]; if( $method === 'POST' ) { $response = $this->post( $request_data, $args ); } else { $response = $this->fetch( $request_data, $args ); } } else { throw $exception; } } return $response; } } diff --git a/include/wb/Claim.php b/include/wb/Claim.php index 086d3cb..b53cd8e 100644 --- a/include/wb/Claim.php +++ b/include/wb/Claim.php @@ -1,489 +1,489 @@ . # Wikibase namespace wb; /** * A Claim consists of a Snak and Qualifiers. * * Optionally, it can have qualifiers. * * @see https://www.wikidata.org/wiki/Wikidata:Glossary#Claim */ class Claim { /** * When a claim has not a main snak, we assume that it has this dummy property. * * It's very useful to send claims to be deleted. It works. asd * * @see https://phabricator.wikimedia.org/T203572 */ const DUMMY_PROPERTY = 'ASD-ASD-ASD'; /** * The 'mainsnak' is a Snak * * @var Snak|null */ private $mainsnak; /** * Claim ID * * @var string|null */ private $id; /** * Claim rank */ private $rank; /** * Qualifiers collector * * @var Snaks */ private $qualifiers; /** * References collector * * @TODO: it has also an hash! * * @var References */ private $references; /** * Constructor * * @param $mainsnak Snak|null Main snak */ public function __construct( $mainsnak = null ) { // eventually initialize mainsnak if( $mainsnak ) { $this->setMainsnak( $mainsnak ); } // initialize snaks collector $this->qualifiers = new Snaks(); // initialize references collector $this->references = new References(); } /** * Check if there is a mainsnak * * @return boolean */ public function hasMainsnak() { return isset( $this->mainsnak ); } /** * Get the mainsnak * * @return Snak|null */ public function getMainsnak() { return $this->mainsnak; } /** * Get a property. Also a dummy one. NOW. asd * * @return string */ public function getPropertyAlsoDummy() { $snak = $this->getMainsnak(); return $snak ? $snak->getProperty() : self::DUMMY_PROPERTY; } /** * Set the mainsnak * * @param $mainsnak Snak|null * @return self */ public function setMainsnak( $mainsnak ) { $this->mainsnak = $mainsnak; return $this; } /** * Set the qualifiers (snaks) * * @param object $qualifiers * @return self */ public function setQualifiers( Snaks $qualifiers ) { $this->qualifiers = $qualifiers; return $this; } /** * Set the references * * @param object $references * @return self */ public function setReferences( References $references ) { $this->references = $references; return $this; } /** * Add a qualifier (snak) * * @param object $qualifier Qualifier (snak) * @return self */ public function addQualifier( Snak $qualifier ) { $this->qualifiers->add( $qualifier ); return $this; } /** * Add a reference * * @param object $reference Reference * @return self */ public function addReference( Reference $reference ) { $this->references->add( $reference ); return $this; } /** * Check if the claim has at least a qualifier * * @return boolean */ public function hasQualifiers() { return !$this->qualifiers->isEmpty(); } /** * Check if the claim has at least a reference * * @return boolean */ public function hasReferences() { return !$this->references->isEmpty(); } /** * Check if there are qualifiers related to a property * * @param $property string e.g. 'P123' * @return boolean */ public function hasQualifiersInProperty( $property ) { return $this->qualifiers->hasInProperty( $property ); } /** * Check if there are references related to a property * * @param $property string e.g. 'P123' * @return boolean */ public function hasReferencesInProperty( $property ) { return $this->references->hasInProperty( $property ); } /** * Get all the qualifiers indexed by property (they are snaks) * * @return array */ public function getQualifiers() { return $this->qualifiers->getAll(); } /** * Get all the qualifiers indexed by property (they are snaks) * * @return array */ public function getReferences() { return $this->references->getAll(); } /** * Get all the qualifiers that are related to a property (they are snaks) * * @param $property string e.g. 'P123' * @return array */ public function getQualifiersInProperty( $property ) { return $this->qualifiers->getInProperty( $property ); } /** * Get all the references that are related to a property (they are snaks) * * @param $property string e.g. 'P123' * @return array */ public function getReferencesInProperty( $property ) { return $this->references->getInProperty( $property ); } /** * Check if there is an ID * * @return boolean */ public function hasID() { return isset( $this->id ); } /** * Set the claim ID * * @param $id string * @return string */ public function setID( $id ) { $this->id = $id; return $this; } /** * Get the claim ID * * @return string */ public function getID() { if( !$this->hasID() ) { throw new \Exception( 'missing id' ); } return $this->id; } /** * Check if the Rank is set * * @return boolean */ public function hasRank() { return isset( $this->rank ); } /** * Get the claim rank * * @return string */ public function getRank() { return $this->rank; } /** * Set the Claim rank * * @param string $rank * @return self */ public function setRank( $rank ) { $this->rank = $rank; return $this; } /** * Check if the Rank of the Claim is 'deprecated' * * @return boolean */ public function isDeprecated() { return $this->getRank() === 'deprecated'; } /** * Check if this claim is marked for removal * * @return array */ public function isMarkedForRemoval() { return isset( $this->remove ) && $this->remove; } /** * Mark this claim as to be remove * * @see https://www.wikidata.org/w/api.php?action=help&modules=wbeditentity * @return self */ public function markForRemoval() { $this->remove = 1; return $this; } /** * Set the rank as "preferred" * * @return self */ public function setRankPreferred() { return $this->setRank( 'preferred' ); } /** * Set the rank as "deprecated" * * @return self */ public function setRankDeprecated() { return $this->setRank( 'deprecated' ); } /** * Clone this claim and obtain a claim marked for removal * * @return self */ public function cloneForRemoval() { return ( new self() ) ->setID( $this->getID() ) ->markForRemoval(); } /** * Create a claim from raw data returned from API responses * * @param $data array * @return self */ public static function createFromData( $data ) { // wtf is this shit if( ! isset( $data['mainsnak'] ) ) { - throw new WrongDataException( __CLASS__ ); + throw new WrongDataException( self::class ); } // initialize the claim $claim = new static( Snak::createFromData( $data[ 'mainsnak' ] ) ); // add qualifiers if( isset( $data['qualifiers'] ) ) { foreach( $data['qualifiers'] as $property => $qualifier_raws ) { foreach( $qualifier_raws as $qualifier_raw ) { $qualifier = Snak::createFromData( $qualifier_raw ); $claim->addQualifier( $qualifier ); } } } // add references if( isset( $data['references'] ) ) { $claim->setReferences( References::createFromData( $data['references'] ) ); } // claim ID if( isset( $data[ 'id' ] ) ) { $claim->setID( $data[ 'id' ] ); } // set rank if( isset( $data['rank'] ) ) { $claim->setRank( $data['rank'] ); } return $claim; } /** * Convert this object to an associative array suitable for JSON encoding * * @return array */ public function toData() { $data = []; // mainsnak if( $this->hasMainsnak() ) { $data['mainsnak'] = $this->getMainsnak()->toData(); } // id if( $this->hasID() ) { $data['id'] = $this->getID(); } // rank if( $this->hasRank() ) { $data['rank'] = $this->getRank(); } // qualifiers if( $this->hasQualifiers() ) { $data['qualifiers'] = $this->qualifiers->toData(); } // references if( $this->hasReferences() ) { $data['references'] = $this->references->toData(); } return $data; } /** * Get a wikitext-compatible version of this value * * This may be awared about which is the wiki that will contain this value, * in order to properly choose a correct permalink in wikilinks etc. * * See https://gitpull.it/T221 * * @param $site You can eventually specify in which site you want to print this value */ public function toPrintableWikitext( \mw\Site $site = null ) { // if it's a Snak, just print the DataValue $snak = $this->getMainsnak(); if( $snak ) { return $snak ->getDataValue() ->toPrintableWikitext( $site ); } // eventually show that this Claim is marked for removal $id = $this->getID(); if( $id && $this->isMarkedForRemoval() ) { return "remove claim id = $id"; } // I really can't figure out what do you want to do with me throw new \Exception( 'empty claim' ); } /** * @override */ public function __toString() { throw new Exception("asd"); return $this->toPrintableWikitext(); } } diff --git a/include/wb/DataValue.php b/include/wb/DataValue.php index e976f89..d656b70 100644 --- a/include/wb/DataValue.php +++ b/include/wb/DataValue.php @@ -1,121 +1,121 @@ . # Wikibase namespace wb; /** * A generic DataValue is part of a Snak */ class DataValue { /** * Type of the DataValue * * @var string */ private $type; /** * Value of the DataValue * * @var array */ private $value; /** * Constructor * * @param $type string Type * @param $value mixed Value */ public function __construct( $type, $value ) { $this->setType( $type ) ->setValue( $value ); } /** * Get the type * * @return string */ public function getType() { return $this->type; } /** * Get the value * * @return mixed */ public function getValue() { return $this->value; } /** * Set the type */ public function setType( $type ) { $this->type = $type; return $this; } /** * Set the value * * @param mixed $value * @return self */ public function setValue( $value ) { $this->value = $value; return $this; } /** * Static constructor from a standard object * * @param object $data * @return self */ public static function createFromData( $data ) { if( ! isset( $data['type'], $data['value'] ) ) { - throw new WrongDataException( __CLASS__ ); + throw new WrongDataException( self::class ); } return new self( $data['type'], $data['value'] ); } /** * Export this object to an associative array suitable for JSON-encoding * * @return array */ public function toData() { return [ 'type' => $this->getType(), 'value' => $this->getValue(), ]; } /** * Get this object in form of a string * * @return string */ public function __toString() { return json_encode( $this->getValue() ); } } diff --git a/include/wb/Label.php b/include/wb/Label.php index 4ffdfa6..5cf8b92 100644 --- a/include/wb/Label.php +++ b/include/wb/Label.php @@ -1,69 +1,69 @@ . # Wikibase namespace wb; /** * An entity Label. * * @see https://www.wikidata.org/wiki/Wikidata:Glossary#Label */ class Label { var $language; var $value; public function __construct( $language, $value ) { $this->setLanguage( $language ) ->setValue( $value ); } public function getLanguage() { return $this->language; } public function getValue() { return $this->value; } public function setLanguage( $language ) { $this->language = $language; return $this; } public function setValue( $value ) { $this->value = $value; return $this; } public static function createFromData( $data ) { if( ! isset( $data['language'], $data['value'] ) ) { - throw new WrongDataException( __CLASS__ ); + throw new WrongDataException( self::class ); } return new static( $data['language'], $data['value'] ); } /** * String rappresentation * * @return string */ public function __toString() { return sprintf( '%s: %s', $this->getLanguage(), $this->getValue() ); } } diff --git a/include/wb/Reference.php b/include/wb/Reference.php index c901c99..b62f168 100644 --- a/include/wb/Reference.php +++ b/include/wb/Reference.php @@ -1,232 +1,232 @@ . # Wikibase namespace wb; /** * Reference * * A reference is a collection of snaks. */ class Reference { /** * Identifier of this reference * * @var string */ private $hash; /** * All the snaks * * @var object */ private $snaks; /** * Snaks order * * It's an array of property names. e.g. [ 'P123' , ... ] * * @var array */ private $snaksOrder; /** * Constructor * * @param array $snaks */ public function __construct( $snaks = [] ) { $this->snaks = new Snaks( $snaks ); } /** * Check if the snak has an hash * * @return bool */ public function hasHash() { return isset( $this->hash ); } /** * Get the hash * * @return string|null */ public function getHash() { return $this->hash; } /** * Set the hash * * @param $hash string * @return self */ public function setHash( $hash ) { $this->hash = $hash; return $this; } /** * Add a snak * * @param object $snak * @return self */ public function add( Snak $snak ) { $this->snaks->add( $snak ); return $this; } /** * Count all the snaks * * @return int */ public function count() { return $this->snaks->count(); } /** * Get all the snaks in a certain property * * @param $property string * @return array */ public function getSnaksInProperty( $property ) { return $this->snaks->getInProperty( $property ); } /** * Check if there are snaks in a certain property * * @param $property string * @return bool */ public function hasSnaksInProperty( $property ) { return $this->snaks->hasInProperty( $property ); } /** * Get all the snaks indexed by property * * @return array */ public function getSnaksByProperty() { return $this->snaks->getAllByProperty(); } /** * Check if the snaks order is specified * * @return boolean */ public function hasSnaksOrder() { return isset( $this->snaksOrder ); } /** * Check if the reference is empty * * @return boolean */ public function isEmpty() { return $this->snaks->isEmpty(); } /** * Get the snaks order * * @return array|null */ public function getSnaksOrder() { return $this->snaksOrder; } /** * Set the snaks order * * @param array $properties * @return self */ public function setSnaksOrder( $properties ) { $this->snaksOrder = $properties; return $this; } /** * Constructor from a raw object retrieved from API results * * @param object $reference_raw * @return self */ public static function createFromData( $reference_raw ) { $reference = new self(); // reference snaks if( !isset( $reference_raw['snaks'] ) ) { - throw new WrongDataException( __CLASS__, 'no snaks field' ); + throw new WrongDataException( self::class, 'no snaks field' ); } foreach( $reference_raw['snaks'] as $property => $snaks_raw ) { foreach( $snaks_raw as $snak_raw ) { $snak = Snak::createFromData( $snak_raw ); $reference->add( $snak ); } } // reference hash if( isset( $reference_raw['hash'] ) ) { $reference->setHash( $reference_raw['hash'] ); } // reference snaks order (array of properties) if( isset( $reference_raw['snaks-order'] ) ) { $reference->setSnaksOrder( $reference_raw['snaks-order'] ); } return $reference; } /** * Convert this object to an associative array suitable for JSON encoding * * @return array */ public function toData() { $data = []; // reference hash if( $this->hasHash() ) { $data['hash'] = $this->getHash(); } // reference snaks $data['snaks'] = $this->snaks->toData(); // snaks order (property list) if( $this->hasSnaksOrder() ) { $data['snaks-order'] = $this->getSnaksOrder(); } return $data; } } diff --git a/include/wb/Sitelink.php b/include/wb/Sitelink.php index 868e0fa..a539e92 100644 --- a/include/wb/Sitelink.php +++ b/include/wb/Sitelink.php @@ -1,148 +1,148 @@ . # Wikibase namespace wb; /** * An entity Sitelink * * @see https://www.wikidata.org/wiki/Wikidata:Glossary#Sitelink */ class Sitelink { /** * @var string */ private $site; /** * @var string */ private $title; /** * @var array */ private $badges = []; /** * Constructor * * @param $site string * @param $title string */ public function __construct( $site, $title, $badges = [] ) { $this->setsite( $site ) ->setTitle( $title ) ->setBadges( $badges ); } /** * Get the site * * @return string */ public function getSite() { return $this->site; } /** * Get the title * * @return string */ public function getTitle() { return $this->title; } /** * Set the site * * @param $site string * @return self */ public function setSite( $site ) { $this->site = $site; return $this; } /** * Get the badges * * @return array */ public function getBadges() { return $this->badges; } /** * Set the title * * @param $site string * @return self */ public function setTitle( $title ) { $this->title = $title; return $this; } /** * Set the badges * * @param $badges array * @return self */ public function setBadges( $badges ) { $this->badges = $badges; return $this; } /** * Static constructor from an array of data * * @param $data array * @return self */ public static function createFromData( $data ) { if( ! isset( $data[ 'site' ], $data[ 'title' ] ) ) { - throw new WrongDataException( __CLASS__ ); + throw new WrongDataException( self::class ); } return new self( $data[ 'site' ], $data[ 'title' ] ); } /** * Get as an associative array * * @return array */ public function toData() { return [ 'site' => $this->getSite(), 'title' => $this->getTitle(), ]; } /** * String rappresentation * * @return string */ public function __toString() { return sprintf( '%s: %s', $this->getSite(), $this->getTitle() ); } } diff --git a/include/wb/Sitelinks.php b/include/wb/Sitelinks.php index 1785776..920da94 100644 --- a/include/wb/Sitelinks.php +++ b/include/wb/Sitelinks.php @@ -1,137 +1,137 @@ . # Wikibase namespace wb; /** * Sitelink collector */ class Sitelinks { /** * @var array */ private $sitelinks = []; /** * Constructor * * @param $sitelinks array */ public function __construct( $sitelinks = [] ) { foreach( $sitelinks as $sitelink ) { $this->set( $sitelink ); } } /** * Get a certain site * * @param $site string * @return Sitelink|false */ public function get( $site ) { if( isset( $this->sitelinks[ $site ] ) ) { return $this->sitelinks[ $site ]; } return false; } /** * Does it have a certain sitelink? * * @param $site string * @return bool */ public function have( $site ) { return false !== $this->get( $site ); } /** * Set/add a certain sitelink * * @param $sitelink Sitelink * @return self */ public function set( Sitelink $sitelink ) { $this->sitelinks[ $sitelink->getSite() ] = $sitelink; return $this; } /** * Get all the sitelinks * * @return array */ public function getAll() { return $this->sitelinks; } /** * Get as an associative array * * @return array */ public function toData() { $all = $this->getAll(); foreach( $all as $site => $sitelink ) { $all[ $site ] = $sitelink->toData(); } return $all; } /** * Create from an associative array (JSON response part) * * @param $data array * @return self */ public static function createFromData( $data ) { if( ! is_array( $data ) ) { - throw new WrongDataException( __CLASS__ ); + throw new WrongDataException( self::class ); } $sitelinks = new self(); foreach( $data as $sitelink ) { $sitelinks->set( Sitelink::createFromData( $sitelink ) ); } return $sitelinks; } /** * Get all the sites imploded * * @param $glue string * @return string */ protected function getImplodedSites( $glue = ',' ) { $codes = []; foreach( $this->getAll() as $sitelink ) { $codes[] = $sitelink->getSite(); } return implode( $glue, $codes ); } /** * String rappresentation * * @return string */ public function __toString() { return sprintf( 'sitelink: %s', $this->getImplodedsites() ); } } diff --git a/include/wb/Snak.php b/include/wb/Snak.php index 0e72969..5d4ed10 100644 --- a/include/wb/Snak.php +++ b/include/wb/Snak.php @@ -1,307 +1,307 @@ . # Wikibase namespace wb; /** * A generic Snak is a combination of a property and a datatype + datavalue. * * A Snak is part of a Claim or a Reference. It's based on a DataValue. */ class Snak { private $hash; private $snaktype; private $property; private $datatype; private $datavalue; /** * @param $snaktype string * @param $property string * @param $datatype string * @param $datavalue mixed */ public function __construct( $snaktype, $property, $datatype, $datavalue = null ) { $this->setSnakType( $snaktype ) ->setProperty( $property ) ->setDataType( $datatype ); if( null !== $datavalue ) { $this->setDataValue( $datavalue ); } } /** * Get the property * * @return string */ public function getProperty() { return $this->property; } /** * Get the snak type */ public function getSnakType() { return $this->snaktype; } /** * Get the data type */ public function getDataType() { return $this->datatype; } /** * Get the data value * * @return DataValue */ public function getDataValue() { return $this->datavalue; } /** * Set the snak type * * @param $snaktype * @param self */ public function setSnakType( $snaktype ) { $this->snaktype = $snaktype; return $this; } /** * Set the property * * @param $property string * @param self */ public function setProperty( $property ) { $this->property = $property; return $this; } /** * Get an human property label, if available in cache */ public function getPropertyLabel() { return self::propertyLabel( $this->getProperty() ); } /** * Set the data type * * @param $datatype * @param self */ public function setDataType( $datatype ) { $this->datatype = $datatype; return $this; } /** * Set the data value * * @param $datavalue DataValue * @param self */ public function setDataValue( DataValue $datavalue ) { $this->datavalue = $datavalue; return $this; } /** * Check if the snak has an hash * * @return bool */ public function hasHash() { return isset( $this->hash ); } /** * Get the hash * * @return string|null */ public function getHash() { return $this->hash; } /** * Set the hash * * @param $hash string * @return self */ public function setHash( $hash ) { $this->hash = $hash; return $this; } /** * Get a wikilink to this property * * This may be awared about which is the wiki that will contain this value, * in order to properly choose a correct permalink in wikilinks etc. * * See https://gitpull.it/T221 * * @param $site object You can eventually specify in which site you want to print this value * @return string */ protected function getPropertyWLink( \mw\Site $site = null ) { /** * If you are on every wiki but Wikidata, * links to items and properties will fail without * an interwiki prefix. * * See https://gitpull.it/T221 */ $prefix = ''; if( $site && $site::UID !== 'wikidatawiki' ) { $prefix = 'wikidata:'; } $prop = $this->getProperty(); $label = $this->getPropertyLabel(); if( !$label ) { $label = $prop; } return sprintf( '[[%sP:%s|%s]]', $prefix, $prop, $label ); } /** * Try to read the property label from the cache * * @TODO: ask also the site * @return string|false */ public static function propertyLabel( $property ) { return \wm\Wikidata::propertyLabel( $property ); } /** * Create a snak from raw data * * @param $data array * @return self */ public static function createFromData( $data ) { /** * Check if the data has these attributes * * Note that Wikimedia Commons' Structured Data may * not return any 'datatype'. * * See https://gitpull.it/T223 * See https://phabricator.wikimedia.org/T246809 */ $required_attributes = [ 'snaktype', 'property', // 'datatype', ]; foreach( $required_attributes as $required_attribute ) { if( !isset( $data[ $required_attribute ] ) ) { - throw new WrongDataException( __CLASS__, "missing $required_attribute" ); + throw new WrongDataException( self::class, "missing $required_attribute" ); } } // create the Snak $snak = new self( $data['snaktype'], $data['property'], $data['datatype'] ?? null ); // eventually set the DataValue if( isset( $data['datavalue'] ) ) { $snak->setDataValue( DataValue::createFromData( $data['datavalue'] ) ); } // eventually set the hash if( isset( $data['hash'] ) ) { $snak->setHash( $data['hash'] ); } // that's all return $snak; } /** * Convert this object to an associative array suitable for JSON encoding * * @return array */ public function toData() { $data = []; // it may have an hash if( $this->hasHash() ) { $data['hash'] = $this->getHash(); } $data['snaktype'] = $this->getSnakType(); $data['property'] = $this->getProperty(); $data['datatype'] = $this->getDataType(); $data['datavalue'] = $this->getDataValue(); if( $data['datavalue'] ) { $data['datavalue'] = $data['datavalue']->toData(); } return $data; } /** * Get a wikitext-compatible version of this value * * This may be awared about which is the wiki that will contain this value, * in order to properly choose a correct permalink in wikilinks etc. * * See https://gitpull.it/T221 * * @param $site object You can eventually specify in which site you want to print this value * @return string */ public function toPrintableWikitext( \mw\Site $site = null ) { return sprintf( '%s: %s', $this->getPropertyWLink( $site ), $this->getDataValue()->toPrintableWikitext( $site ) ); } /** * @return string */ public function __toString() { return $this->toPrintableWikitext(); } } diff --git a/include/wb/Statement.php b/include/wb/Statement.php index c419865..4d999e2 100644 --- a/include/wb/Statement.php +++ b/include/wb/Statement.php @@ -1,149 +1,149 @@ . # Wikibase namespace wb; /** * A Statement is a type of Claim with references and a rank. * * @see https://www.wikidata.org/wiki/Wikidata:Glossary#Statement */ class Statement extends Claim { /** * ID of the statement (if any) * * @var string|null */ private $id; /** * Type of the statement * * I think that it's hardcoded to 'statement' in Wikibase. * * @var string */ private $type = 'statement'; public function __construct( $mainsnak = null ) { parent::__construct( $mainsnak ); // set a default rank $this->setRank( 'normal' ); } /** * Get the type * * @return string */ public function getType() { return $this->type; } /** * Check if this statement has an ID * * @return boolean */ public function hasID() { return isset( $this->id ); } /** * Get the ID (if any) * * @return string|null */ public function getID() { return $this->id; } /** * Get the ID (if any) * * @return string|null */ public function setID( $id ) { $this->id = $id; } /** * Set the type * * @param string $type * @return self */ public function setType( $type ) { $this->type = $type; return $this; } /** * Create a statement from raw data returned from API responses * * @param $data array * @return self */ public static function createFromData( $data ) { if( ! isset( $data['type'], $data['rank'] ) ) { - throw new WrongDataException( __CLASS__ ); + throw new WrongDataException( self::class ); } $statement = parent::createFromData( $data ); $statement->setType( $data['type'] ); if( isset( $data['rank'] ) ) { $statement->setRank( $data['rank'] ); } if( $data['id'] ) { $statement->setID( $data['id'] ); } if( isset( $data['references'] ) ) { $statement->setReferences( References::createFromData( $data['references'] ) ); } return $statement; } /** * Convert this object to an associative array suitable for JSON encoding * * @return array */ public function toData() { $data = parent::toData(); // statement ID if( $this->hasID() ) { $data['id'] = $this->getID(); } // statement type $data['type'] = $this->getType(); // statement rank $data['rank'] = $this->getRank(); return $data; } }