This project does not seem to handle request data directly as such no vulnerable execution paths were found.
include, or for example
via PHP's auto-loading mechanism.
These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
| 1 | <?php |
||
| 2 | |||
| 3 | namespace Wikibase\Repo\LinkedData; |
||
| 4 | |||
| 5 | use ApiFormatBase; |
||
| 6 | use ApiMain; |
||
| 7 | use ApiResult; |
||
| 8 | use DerivativeContext; |
||
| 9 | use DerivativeRequest; |
||
| 10 | use MWException; |
||
| 11 | use PageProps; |
||
| 12 | use RequestContext; |
||
| 13 | use Serializers\Serializer; |
||
| 14 | use SiteLookup; |
||
| 15 | use Wikibase\DataModel\Entity\EntityId; |
||
| 16 | use Wikibase\DataModel\Entity\EntityRedirect; |
||
| 17 | use Wikibase\DataModel\SerializerFactory; |
||
| 18 | use Wikibase\DataModel\Services\Lookup\EntityLookup; |
||
| 19 | use Wikibase\DataModel\Services\Lookup\PropertyDataTypeLookup; |
||
| 20 | use Wikibase\Lib\Store\EntityRevision; |
||
| 21 | use Wikibase\Lib\Store\EntityTitleLookup; |
||
| 22 | use Wikibase\Lib\Store\RedirectRevision; |
||
| 23 | use Wikibase\Repo\Api\ResultBuilder; |
||
| 24 | use Wikibase\Repo\Rdf\EntityRdfBuilderFactory; |
||
| 25 | use Wikibase\Repo\Rdf\HashDedupeBag; |
||
| 26 | use Wikibase\Repo\Rdf\RdfBuilder; |
||
| 27 | use Wikibase\Repo\Rdf\RdfProducer; |
||
| 28 | use Wikibase\Repo\Rdf\RdfVocabulary; |
||
| 29 | use Wikibase\Repo\Rdf\ValueSnakRdfBuilderFactory; |
||
| 30 | use Wikimedia\Purtle\RdfWriterFactory; |
||
| 31 | |||
| 32 | /** |
||
| 33 | * Service for serializing entity data. |
||
| 34 | * |
||
| 35 | * Note that we are using the API's serialization facility to ensure a consistent external |
||
| 36 | * representation of data entities. Using the ContentHandler to serialize the entity would expose |
||
| 37 | * internal implementation details. |
||
| 38 | * |
||
| 39 | * For RDF output, this relies on the RdfBuilder class. |
||
| 40 | * |
||
| 41 | * @license GPL-2.0-or-later |
||
| 42 | * @author Daniel Kinzler |
||
| 43 | * @author Thomas Pellissier Tanon |
||
| 44 | * @author Anja Jentzsch < [email protected] > |
||
| 45 | */ |
||
| 46 | class EntityDataSerializationService { |
||
| 47 | |||
| 48 | /** |
||
| 49 | * @var EntityLookup|null |
||
| 50 | */ |
||
| 51 | private $entityLookup = null; |
||
| 52 | |||
| 53 | /** |
||
| 54 | * @var EntityTitleLookup |
||
| 55 | */ |
||
| 56 | private $entityTitleLookup; |
||
| 57 | |||
| 58 | /** |
||
| 59 | * @var SerializerFactory |
||
| 60 | */ |
||
| 61 | private $serializerFactory; |
||
| 62 | |||
| 63 | /** |
||
| 64 | * @var Serializer |
||
| 65 | */ |
||
| 66 | private $entitySerializer; |
||
| 67 | |||
| 68 | /** |
||
| 69 | * @var PropertyDataTypeLookup |
||
| 70 | */ |
||
| 71 | private $propertyLookup; |
||
| 72 | |||
| 73 | /** |
||
| 74 | * @var EntityDataFormatProvider |
||
| 75 | */ |
||
| 76 | private $entityDataFormatProvider; |
||
| 77 | |||
| 78 | /** |
||
| 79 | * @var RdfWriterFactory |
||
| 80 | */ |
||
| 81 | private $rdfWriterFactory; |
||
| 82 | |||
| 83 | /** |
||
| 84 | * @var SiteLookup |
||
| 85 | */ |
||
| 86 | private $siteLookup; |
||
| 87 | |||
| 88 | /** |
||
| 89 | * @var RdfVocabulary |
||
| 90 | */ |
||
| 91 | private $rdfVocabulary; |
||
| 92 | |||
| 93 | /** |
||
| 94 | * @var ValueSnakRdfBuilderFactory |
||
| 95 | */ |
||
| 96 | private $valueSnakRdfBuilderFactory; |
||
| 97 | |||
| 98 | /** |
||
| 99 | * @var EntityRdfBuilderFactory |
||
| 100 | */ |
||
| 101 | private $entityRdfBuilderFactory; |
||
| 102 | |||
| 103 | public function __construct( |
||
| 104 | EntityLookup $entityLookup, |
||
| 105 | EntityTitleLookup $entityTitleLookup, |
||
| 106 | PropertyDataTypeLookup $propertyLookup, |
||
| 107 | ValueSnakRdfBuilderFactory $valueSnakRdfBuilderFactory, |
||
| 108 | EntityRdfBuilderFactory $entityRdfBuilderFactory, |
||
| 109 | EntityDataFormatProvider $entityDataFormatProvider, |
||
| 110 | SerializerFactory $serializerFactory, |
||
| 111 | Serializer $entitySerializer, |
||
| 112 | SiteLookup $siteLookup, |
||
| 113 | RdfVocabulary $rdfVocabulary |
||
| 114 | ) { |
||
| 115 | $this->entityLookup = $entityLookup; |
||
| 116 | $this->entityTitleLookup = $entityTitleLookup; |
||
| 117 | $this->propertyLookup = $propertyLookup; |
||
| 118 | $this->valueSnakRdfBuilderFactory = $valueSnakRdfBuilderFactory; |
||
| 119 | $this->entityRdfBuilderFactory = $entityRdfBuilderFactory; |
||
| 120 | $this->entityDataFormatProvider = $entityDataFormatProvider; |
||
| 121 | $this->serializerFactory = $serializerFactory; |
||
| 122 | $this->entitySerializer = $entitySerializer; |
||
| 123 | $this->siteLookup = $siteLookup; |
||
| 124 | $this->rdfVocabulary = $rdfVocabulary; |
||
| 125 | |||
| 126 | $this->rdfWriterFactory = new RdfWriterFactory(); |
||
| 127 | } |
||
| 128 | |||
| 129 | /** |
||
| 130 | * Output entity data. |
||
| 131 | * |
||
| 132 | * @param string $format The name (mime type of file extension) of the format to use |
||
| 133 | * @param EntityRevision $entityRevision The entity |
||
| 134 | * @param RedirectRevision|null $followedRedirect The redirect that led to the entity, or null |
||
| 135 | * @param EntityId[] $incomingRedirects Incoming redirects to include in the output |
||
| 136 | * @param string|null $flavor The type of the output provided by serializer |
||
| 137 | * |
||
| 138 | * @return array tuple of ( $data, $contentType ) |
||
| 139 | * @throws MWException |
||
| 140 | */ |
||
| 141 | public function getSerializedData( |
||
| 142 | $format, |
||
| 143 | EntityRevision $entityRevision, |
||
| 144 | RedirectRevision $followedRedirect = null, |
||
| 145 | array $incomingRedirects = [], |
||
| 146 | $flavor = null |
||
| 147 | ) { |
||
| 148 | |||
| 149 | $formatName = $this->entityDataFormatProvider->getFormatName( $format ); |
||
| 150 | |||
| 151 | if ( $formatName === null ) { |
||
| 152 | throw new MWException( "Unsupported format: $format" ); |
||
| 153 | } |
||
| 154 | |||
| 155 | $serializer = $this->createApiSerializer( $formatName ); |
||
| 156 | |||
| 157 | if ( $serializer !== null ) { |
||
| 158 | $data = $this->getApiSerialization( $entityRevision, $serializer ); |
||
| 159 | $contentType = $serializer->getIsHtml() ? 'text/html' : $serializer->getMimeType(); |
||
| 160 | } else { |
||
| 161 | $rdfBuilder = $this->createRdfBuilder( $formatName, $flavor ); |
||
| 162 | |||
| 163 | if ( $rdfBuilder === null ) { |
||
| 164 | throw new MWException( "Could not create serializer for $formatName" ); |
||
| 165 | } |
||
| 166 | |||
| 167 | $data = $this->rdfSerialize( $entityRevision, $followedRedirect, $incomingRedirects, $rdfBuilder, $flavor ); |
||
| 168 | |||
| 169 | $mimeTypes = $this->rdfWriterFactory->getMimeTypes( $formatName ); |
||
| 170 | $contentType = reset( $mimeTypes ); |
||
| 171 | } |
||
| 172 | |||
| 173 | return [ $data, $contentType ]; |
||
| 174 | } |
||
| 175 | |||
| 176 | /** |
||
| 177 | * @param EntityRevision $entityRevision |
||
| 178 | * @param RedirectRevision|null $followedRedirect a redirect leading to the entity for use in the output |
||
| 179 | * @param EntityId[] $incomingRedirects Incoming redirects to include in the output |
||
| 180 | * @param RdfBuilder $rdfBuilder |
||
| 181 | * @param string|null $flavor The type of the output provided by serializer |
||
| 182 | * |
||
| 183 | * @return string RDF |
||
| 184 | */ |
||
| 185 | private function rdfSerialize( |
||
| 186 | EntityRevision $entityRevision, |
||
| 187 | ?RedirectRevision $followedRedirect, |
||
| 188 | array $incomingRedirects, |
||
| 189 | RdfBuilder $rdfBuilder, |
||
| 190 | $flavor = null |
||
| 191 | ) { |
||
| 192 | $rdfBuilder->startDocument(); |
||
| 193 | $redir = null; |
||
| 194 | |||
| 195 | if ( $followedRedirect ) { |
||
| 196 | $redir = $followedRedirect->getRedirect(); |
||
| 197 | $rdfBuilder->addEntityRedirect( $redir->getEntityId(), $redir->getTargetId() ); |
||
| 198 | |||
| 199 | if ( $followedRedirect->getRevisionId() > 0 ) { |
||
| 200 | $rdfBuilder->addEntityRevisionInfo( |
||
| 201 | $redir->getEntityId(), |
||
| 202 | $followedRedirect->getRevisionId(), |
||
| 203 | $followedRedirect->getTimestamp() |
||
| 204 | ); |
||
| 205 | } |
||
| 206 | } |
||
| 207 | |||
| 208 | if ( $followedRedirect && $flavor === 'dump' ) { |
||
| 209 | // For redirects, don't output the target entity data if the "dump" flavor is requested. |
||
| 210 | // @todo: In this case, avoid loading the Entity all together. |
||
| 211 | // However we want to output the revisions for redirects |
||
| 212 | } else { |
||
| 213 | $rdfBuilder->addEntityRevisionInfo( |
||
| 214 | $entityRevision->getEntity()->getId(), |
||
|
0 ignored issues
–
show
|
|||
| 215 | $entityRevision->getRevisionId(), |
||
| 216 | $entityRevision->getTimestamp() |
||
| 217 | ); |
||
| 218 | |||
| 219 | $rdfBuilder->addEntityPageProps( $entityRevision->getEntity()->getId() ); |
||
|
0 ignored issues
–
show
It seems like
$entityRevision->getEntity()->getId() can be null; however, addEntityPageProps() does not accept null, maybe add an additional type check?
Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code: /** @return stdClass|null */
function mayReturnNull() { }
function doesNotAcceptNull(stdClass $x) { }
// With potential error.
function withoutCheck() {
$x = mayReturnNull();
doesNotAcceptNull($x); // Potential error here.
}
// Safe - Alternative 1
function withCheck1() {
$x = mayReturnNull();
if ( ! $x instanceof stdClass) {
throw new \LogicException('$x must be defined.');
}
doesNotAcceptNull($x);
}
// Safe - Alternative 2
function withCheck2() {
$x = mayReturnNull();
if ($x instanceof stdClass) {
doesNotAcceptNull($x);
}
}
Loading history...
|
|||
| 220 | |||
| 221 | $rdfBuilder->addEntity( $entityRevision->getEntity() ); |
||
| 222 | $rdfBuilder->resolveMentionedEntities( $this->entityLookup ); |
||
|
0 ignored issues
–
show
It seems like
$this->entityLookup can be null; however, resolveMentionedEntities() does not accept null, maybe add an additional type check?
Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code: /** @return stdClass|null */
function mayReturnNull() { }
function doesNotAcceptNull(stdClass $x) { }
// With potential error.
function withoutCheck() {
$x = mayReturnNull();
doesNotAcceptNull($x); // Potential error here.
}
// Safe - Alternative 1
function withCheck1() {
$x = mayReturnNull();
if ( ! $x instanceof stdClass) {
throw new \LogicException('$x must be defined.');
}
doesNotAcceptNull($x);
}
// Safe - Alternative 2
function withCheck2() {
$x = mayReturnNull();
if ($x instanceof stdClass) {
doesNotAcceptNull($x);
}
}
Loading history...
|
|||
| 223 | } |
||
| 224 | |||
| 225 | if ( $flavor !== 'dump' ) { |
||
| 226 | // For $flavor === 'dump' we don't need to output incoming redirects. |
||
| 227 | |||
| 228 | $targetId = $entityRevision->getEntity()->getId(); |
||
| 229 | $this->addIncomingRedirects( $targetId, $redir, $incomingRedirects, $rdfBuilder ); |
||
|
0 ignored issues
–
show
It seems like
$targetId defined by $entityRevision->getEntity()->getId() on line 228 can be null; however, Wikibase\Repo\LinkedData...:addIncomingRedirects() does not accept null, maybe add an additional type check?
Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code: /** @return stdClass|null */
function mayReturnNull() { }
function doesNotAcceptNull(stdClass $x) { }
// With potential error.
function withoutCheck() {
$x = mayReturnNull();
doesNotAcceptNull($x); // Potential error here.
}
// Safe - Alternative 1
function withCheck1() {
$x = mayReturnNull();
if ( ! $x instanceof stdClass) {
throw new \LogicException('$x must be defined.');
}
doesNotAcceptNull($x);
}
// Safe - Alternative 2
function withCheck2() {
$x = mayReturnNull();
if ($x instanceof stdClass) {
doesNotAcceptNull($x);
}
}
Loading history...
|
|||
| 230 | } |
||
| 231 | |||
| 232 | $rdfBuilder->finishDocument(); |
||
| 233 | |||
| 234 | return $rdfBuilder->getRDF(); |
||
| 235 | } |
||
| 236 | |||
| 237 | /** |
||
| 238 | * @param EntityId $targetId |
||
| 239 | * @param EntityRedirect|null $followedRedirect The followed redirect, will be omitted from the |
||
| 240 | * output. |
||
| 241 | * @param EntityId[] $incomingRedirects |
||
| 242 | * @param RdfBuilder $rdfBuilder |
||
| 243 | */ |
||
| 244 | private function addIncomingRedirects( |
||
| 245 | EntityId $targetId, |
||
| 246 | ?EntityRedirect $followedRedirect, |
||
| 247 | array $incomingRedirects, |
||
| 248 | RdfBuilder $rdfBuilder |
||
| 249 | ) { |
||
| 250 | foreach ( $incomingRedirects as $rId ) { |
||
| 251 | // don't add the followed redirect again |
||
| 252 | if ( !$followedRedirect || !$followedRedirect->getEntityId()->equals( $rId ) ) { |
||
| 253 | $rdfBuilder->addEntityRedirect( $rId, $targetId ); |
||
| 254 | } |
||
| 255 | } |
||
| 256 | } |
||
| 257 | |||
| 258 | /** |
||
| 259 | * Returns an ApiMain module that acts as a context for the formatting and serialization. |
||
| 260 | * |
||
| 261 | * @param string $format The desired output format, as a format name that ApiBase understands. |
||
| 262 | * |
||
| 263 | * @return ApiMain |
||
| 264 | */ |
||
| 265 | private function newApiMain( $format ) { |
||
| 266 | // Fake request params to ApiMain, with forced format parameters. |
||
| 267 | // We can override additional parameters here, as needed. |
||
| 268 | $params = [ |
||
| 269 | 'format' => $format, |
||
| 270 | ]; |
||
| 271 | |||
| 272 | $context = new DerivativeContext( RequestContext::getMain() ); //XXX: ugly |
||
| 273 | |||
| 274 | $req = new DerivativeRequest( $context->getRequest(), $params ); |
||
| 275 | $context->setRequest( $req ); |
||
| 276 | |||
| 277 | $api = new ApiMain( $context ); |
||
| 278 | return $api; |
||
| 279 | } |
||
| 280 | |||
| 281 | /** |
||
| 282 | * Creates an API printer that can generate the given output format. |
||
| 283 | * |
||
| 284 | * @param string $formatName The desired serialization format, |
||
| 285 | * as a format name understood by ApiBase or RdfWriterFactory. |
||
| 286 | * |
||
| 287 | * @return ApiFormatBase|null A suitable result printer, or null |
||
| 288 | * if the given format is not supported by the API. |
||
| 289 | */ |
||
| 290 | private function createApiSerializer( $formatName ) { |
||
| 291 | //MediaWiki formats |
||
| 292 | $api = $this->newApiMain( $formatName ); |
||
| 293 | $formatNames = $api->getModuleManager()->getNames( 'format' ); |
||
| 294 | if ( $formatName !== null && in_array( $formatName, $formatNames ) ) { |
||
| 295 | return $api->createPrinterByName( $formatName ); |
||
| 296 | } |
||
| 297 | |||
| 298 | return null; |
||
| 299 | } |
||
| 300 | |||
| 301 | /** |
||
| 302 | * Get the producer setting for current data format |
||
| 303 | * |
||
| 304 | * @param string|null $flavorName |
||
| 305 | * |
||
| 306 | * @return int |
||
| 307 | * @throws MWException |
||
| 308 | */ |
||
| 309 | private function getFlavor( $flavorName ) { |
||
| 310 | switch ( $flavorName ) { |
||
| 311 | case 'simple': |
||
| 312 | return RdfProducer::PRODUCE_TRUTHY_STATEMENTS |
||
| 313 | | RdfProducer::PRODUCE_SITELINKS |
||
| 314 | | RdfProducer::PRODUCE_VERSION_INFO; |
||
| 315 | case 'dump': |
||
| 316 | return RdfProducer::PRODUCE_ALL_STATEMENTS |
||
| 317 | | RdfProducer::PRODUCE_TRUTHY_STATEMENTS |
||
| 318 | | RdfProducer::PRODUCE_QUALIFIERS |
||
| 319 | | RdfProducer::PRODUCE_REFERENCES |
||
| 320 | | RdfProducer::PRODUCE_SITELINKS |
||
| 321 | | RdfProducer::PRODUCE_FULL_VALUES |
||
| 322 | | RdfProducer::PRODUCE_PAGE_PROPS |
||
| 323 | | RdfProducer::PRODUCE_NORMALIZED_VALUES |
||
| 324 | | RdfProducer::PRODUCE_VERSION_INFO; |
||
| 325 | case 'long': |
||
| 326 | return RdfProducer::PRODUCE_ALL_STATEMENTS |
||
| 327 | | RdfProducer::PRODUCE_QUALIFIERS |
||
| 328 | | RdfProducer::PRODUCE_REFERENCES |
||
| 329 | | RdfProducer::PRODUCE_SITELINKS |
||
| 330 | | RdfProducer::PRODUCE_VERSION_INFO; |
||
| 331 | case 'full': |
||
| 332 | case null: |
||
|
0 ignored issues
–
show
|
|||
| 333 | return RdfProducer::PRODUCE_ALL; |
||
| 334 | } |
||
| 335 | |||
| 336 | throw new MWException( "Unsupported flavor: $flavorName" ); |
||
| 337 | } |
||
| 338 | |||
| 339 | /** |
||
| 340 | * Creates an Rdf Serializer that can generate the given output format. |
||
| 341 | * |
||
| 342 | * @param string $format The desired serialization format, as a format name understood by ApiBase or RdfWriterFactory |
||
| 343 | * @param string|null $flavorName Flavor name (used for RDF output) |
||
| 344 | * |
||
| 345 | * @return RdfBuilder|null A suitable result printer, or null |
||
| 346 | * if the given format is not supported. |
||
| 347 | */ |
||
| 348 | private function createRdfBuilder( $format, $flavorName = null ) { |
||
| 349 | $canonicalFormat = $this->rdfWriterFactory->getFormatName( $format ); |
||
| 350 | |||
| 351 | if ( !$canonicalFormat ) { |
||
|
0 ignored issues
–
show
The expression
$canonicalFormat of type string|false is loosely compared to false; this is ambiguous if the string can be empty. You might want to explicitly use === false instead.
In PHP, under loose comparison (like For '' == false // true
'' == null // true
'ab' == false // false
'ab' == null // false
// It is often better to use strict comparison
'' === false // false
'' === null // false
Loading history...
|
|||
| 352 | return null; |
||
| 353 | } |
||
| 354 | |||
| 355 | $rdfWriter = $this->rdfWriterFactory->getWriter( $format ); |
||
| 356 | |||
| 357 | $rdfBuilder = new RdfBuilder( |
||
| 358 | $this->rdfVocabulary, |
||
| 359 | $this->valueSnakRdfBuilderFactory, |
||
| 360 | $this->propertyLookup, |
||
| 361 | $this->entityRdfBuilderFactory, |
||
| 362 | $this->getFlavor( $flavorName ), |
||
| 363 | $rdfWriter, |
||
| 364 | new HashDedupeBag(), |
||
| 365 | $this->entityTitleLookup |
||
| 366 | ); |
||
| 367 | |||
| 368 | $rdfBuilder->setPageProps( PageProps::getInstance() ); |
||
| 369 | |||
| 370 | return $rdfBuilder; |
||
| 371 | } |
||
| 372 | |||
| 373 | /** |
||
| 374 | * Pushes the given $entity into the ApiResult held by the ApiMain module |
||
| 375 | * returned by newApiMain(). Calling $printer->execute() later will output this |
||
| 376 | * result, if $printer was generated from that same ApiMain module, as |
||
| 377 | * createApiPrinter() does. |
||
| 378 | * |
||
| 379 | * @param EntityRevision $entityRevision The entity to convert ot an ApiResult |
||
| 380 | * @param ApiFormatBase $printer The output printer that will be used for serialization. |
||
| 381 | * Used to provide context for generating the ApiResult, and may also be manipulated |
||
| 382 | * to fine-tune the output. |
||
| 383 | * |
||
| 384 | * @return ApiResult |
||
| 385 | */ |
||
| 386 | private function generateApiResult( EntityRevision $entityRevision, ApiFormatBase $printer ) { |
||
| 387 | $res = $printer->getResult(); |
||
| 388 | |||
| 389 | // Make sure result is empty. May still be full if this |
||
| 390 | // function gets called multiple times during testing, etc. |
||
| 391 | $res->reset(); |
||
| 392 | |||
| 393 | $resultBuilder = new ResultBuilder( |
||
| 394 | $res, |
||
| 395 | $this->entityTitleLookup, |
||
| 396 | $this->serializerFactory, |
||
| 397 | $this->entitySerializer, |
||
| 398 | $this->siteLookup, |
||
| 399 | $this->propertyLookup, |
||
| 400 | true // include metadata for the API result printer |
||
| 401 | ); |
||
| 402 | $resultBuilder->addEntityRevision( null, $entityRevision ); |
||
| 403 | |||
| 404 | return $res; |
||
| 405 | } |
||
| 406 | |||
| 407 | /** |
||
| 408 | * Serialize the entity data using the provided format. |
||
| 409 | * |
||
| 410 | * Note that we are using the API's serialization facility to ensure a consistent external |
||
| 411 | * representation of data entities. Using the ContentHandler to serialize the entity would |
||
| 412 | * expose internal implementation details. |
||
| 413 | * |
||
| 414 | * @param EntityRevision $entityRevision the entity to output. |
||
| 415 | * @param ApiFormatBase $printer the printer to use to generate the output |
||
| 416 | * |
||
| 417 | * @return string the serialized data |
||
| 418 | */ |
||
| 419 | private function getApiSerialization( |
||
| 420 | EntityRevision $entityRevision, |
||
| 421 | ApiFormatBase $printer |
||
| 422 | ) { |
||
| 423 | // NOTE: The way the ApiResult is provided to $printer is somewhat |
||
| 424 | // counter-intuitive. Basically, the relevant ApiResult object |
||
| 425 | // is owned by the ApiMain module provided by newApiMain(). |
||
| 426 | |||
| 427 | // Pushes $entity into the ApiResult held by the ApiMain module |
||
| 428 | // TODO: where to put the followed redirect? |
||
| 429 | // TODO: where to put the incoming redirects? See T98039 |
||
| 430 | $this->generateApiResult( $entityRevision, $printer ); |
||
| 431 | |||
| 432 | $printer->initPrinter(); |
||
| 433 | |||
| 434 | // Outputs the ApiResult held by the ApiMain module, which is hopefully the one we added the entity data to. |
||
| 435 | //NOTE: this can and will mess with the HTTP response! |
||
| 436 | $printer->execute(); |
||
| 437 | $data = $printer->getBuffer(); |
||
| 438 | |||
| 439 | $printer->disable(); |
||
| 440 | |||
| 441 | return $data; |
||
| 442 | } |
||
| 443 | |||
| 444 | } |
||
| 445 |
Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code: