1<?php 2 3 4namespace ComboStrap; 5 6 7class PageImages extends MetadataTabular 8{ 9 10 11 const CANONICAL = "page:image"; 12 public const PROPERTY_NAME = 'images'; 13 public const PERSISTENT_NAME = 'images'; 14 public const FIRST_IMAGE_META_RELATION = "firstimage"; 15 public const CONF_DISABLE_FIRST_IMAGE_AS_PAGE_IMAGE = "disableFirstImageAsPageImage"; 16 17 /** 18 * The name should be plural, this one was not 19 */ 20 const OLD_PROPERTY_NAME = "image"; 21 22 23 /** 24 * PageImages constructor. 25 */ 26 public function __construct() 27 { 28 parent::__construct(); 29 } 30 31 32 public static function createForPage(Page $page): PageImages 33 { 34 return (new PageImages()) 35 ->setResource($page); 36 37 } 38 39 public static function create(): Metadata 40 { 41 return new PageImages(); 42 } 43 44 /** 45 * Google accepts several images dimension and ratios 46 * for the same image 47 * We may get an array then 48 */ 49 public function getValueAsPageImagesOrDefault(): array 50 { 51 52 $pageImages = $this->getValueAsPageImages(); 53 if ($pageImages !== null) { 54 return $pageImages; 55 } 56 try { 57 $defaultPageImage = $this->getDefaultImage(); 58 } catch (ExceptionCombo $e) { 59 LogUtility::msg("Error while getting the default page image for the page {$this->getResource()}. The image was not used. Error: {$e->getMessage()}"); 60 return []; 61 } 62 if ($defaultPageImage === null) { 63 return []; 64 } 65 try { 66 return [ 67 PageImage::create($defaultPageImage, $this->getResource()) 68 ]; 69 } catch (ExceptionCombo $e) { 70 LogUtility::msg("Error while creating the default page image ($defaultPageImage) for the page {$this->getResource()}. The image was not used. Error: {$e->getMessage()}"); 71 return []; 72 } 73 74 } 75 76 /** 77 * @return array 78 */ 79 private function toMetadataArray(): ?array 80 { 81 if ($this->pageImages === null) { 82 return null; 83 } 84 $pageImagesMeta = []; 85 ksort($this->pageImages); 86 foreach ($this->pageImages as $pageImage) { 87 $absolutePath = $pageImage->getImage()->getPath()->toAbsolutePath()->toString(); 88 $pageImagesMeta[$absolutePath] = [ 89 PageImagePath::PERSISTENT_NAME => $absolutePath 90 ]; 91 if ($pageImage->getUsages() !== null && $pageImage->getUsages() !== $pageImage->getDefaultUsage()) { 92 $pageImagesMeta[$absolutePath][PageImageUsage::PERSISTENT_NAME] = implode(", ", $pageImage->getUsages()); 93 } 94 }; 95 return array_values($pageImagesMeta); 96 } 97 98 /** 99 * @param $persistentValue 100 * @return PageImage[] 101 * @throws ExceptionCombo 102 */ 103 public function toPageImageArray($persistentValue): array 104 { 105 106 if ($persistentValue === null) { 107 return []; 108 } 109 110 /** 111 * @var Page $page ; 112 */ 113 $page = $this->getResource(); 114 115 if (is_array($persistentValue)) { 116 $images = []; 117 foreach ($persistentValue as $key => $value) { 118 $usage = null; 119 if (is_numeric($key)) { 120 if (is_array($value)) { 121 if (isset($value[PageImageUsage::PERSISTENT_NAME])) { 122 $usage = $value[PageImageUsage::PERSISTENT_NAME]; 123 if (is_string($usage)) { 124 $usage = explode(",", $usage); 125 } 126 } 127 $imagePath = $value[PageImagePath::PERSISTENT_NAME]; 128 } else { 129 $imagePath = $value; 130 } 131 } else { 132 $imagePath = $key; 133 if (is_array($value) && isset($value[PageImageUsage::PERSISTENT_NAME])) { 134 $usage = $value[PageImageUsage::PERSISTENT_NAME]; 135 if (!is_array($usage)) { 136 $usage = explode(",", $usage);; 137 } 138 } 139 } 140 DokuPath::addRootSeparatorIfNotPresent($imagePath); 141 $pageImage = PageImage::create($imagePath, $page); 142 if ($usage !== null) { 143 $pageImage->setUsages($usage); 144 } 145 $images[$imagePath] = $pageImage; 146 147 } 148 return $images; 149 } else { 150 /** 151 * A single path image 152 */ 153 DokuPath::addRootSeparatorIfNotPresent($persistentValue); 154 $images = [$persistentValue => PageImage::create($persistentValue, $page)]; 155 } 156 157 return $images; 158 159 } 160 161 162 /** 163 * @throws ExceptionCombo 164 */ 165 public function setFromStoreValue($value): Metadata 166 { 167 $this->buildFromStoreValue($value); 168 $this->checkImageExistence(); 169 return $this; 170 } 171 172 173 public function getCanonical(): string 174 { 175 return self::CANONICAL; 176 } 177 178 static public function getName(): string 179 { 180 return self::PROPERTY_NAME; 181 } 182 183 static public function getPersistentName(): string 184 { 185 return self::PERSISTENT_NAME; 186 } 187 188 /** 189 * @throws ExceptionCombo 190 */ 191 public function toStoreValue(): ?array 192 { 193 $this->buildCheck(); 194 $this->checkImageExistence(); 195 return parent::toStoreValue(); 196 } 197 198 public function toStoreDefaultValue() 199 { 200 return null; 201 } 202 203 public function getPersistenceType(): string 204 { 205 return MetadataDokuWikiStore::PERSISTENT_METADATA; 206 } 207 208 209 /** 210 * @return PageImage[] 211 */ 212 public function getValueAsPageImages(): ?array 213 { 214 $this->buildCheck(); 215 216 $rows = parent::getValue(); 217 if ($rows === null) { 218 return null; 219 } 220 $pageImages = []; 221 foreach ($rows as $row) { 222 /** 223 * @var PageImagePath $pageImagePath 224 */ 225 $pageImagePath = $row[PageImagePath::getPersistentName()]; 226 try { 227 $pageImage = PageImage::create($pageImagePath->getValue(), $this->getResource()); 228 } catch (ExceptionCombo $e) { 229 LogUtility::msg("Error while creating the page image ($pageImagePath) for the page {$this->getResource()}. The image was not used. Error: {$e->getMessage()}"); 230 continue; 231 } 232 /** 233 * @var PageImageUsage $pageImageUsage 234 */ 235 $pageImageUsage = $row[PageImageUsage::getPersistentName()]; 236 if ($pageImageUsage !== null) { 237 try { 238 $pageImage->setUsages($pageImageUsage->getValue()); 239 } catch (ExceptionCombo $e) { 240 LogUtility::msg("Bad Usage value. Should not happen on get"); 241 } 242 } 243 $pageImages[] = $pageImage; 244 } 245 return $pageImages; 246 } 247 248 /** 249 * @throws ExceptionCombo 250 */ 251 public function addImage(string $wikiImagePath, $usages = null): PageImages 252 { 253 254 $pageImagePath = PageImagePath::createFromParent($this) 255 ->setFromStoreValue($wikiImagePath); 256 $row[PageImagePath::getPersistentName()] = $pageImagePath; 257 if ($usages !== null) { 258 $pageImageUsage = PageImageUsage::createFromParent($this) 259 ->setFromStoreValue($usages); 260 $row[PageImageUsage::getPersistentName()] = $pageImageUsage; 261 } 262 $this->rows[] = $row; 263 264 /** 265 * What fucked up is fucked up 266 * The runtime {@link Doku_Renderer_metadata::_recordMediaUsage()} 267 * ``` 268 * meta['relation']['media'][$src] = $exist 269 * ``` 270 * is only set when parsing to add page to the index 271 */ 272 return $this; 273 } 274 275 276 public function getTab(): string 277 { 278 return MetaManagerForm::TAB_IMAGE_VALUE; 279 } 280 281 282 public function getDescription(): string 283 { 284 return "The illustrative images of the page"; 285 } 286 287 public function getLabel(): string 288 { 289 return "Page Images"; 290 } 291 292 293 public function getMutable(): bool 294 { 295 return true; 296 } 297 298 /** 299 * 300 * We check the existence of the image also when persisting, 301 * not when building 302 * because when moving a media, the images does not exist any more 303 * 304 * We can then build the the pageimages with non-existing images 305 * but we can't save 306 * 307 * @throws ExceptionCombo 308 */ 309 private function checkImageExistence() 310 { 311 if ($this->pageImages !== null) { 312 foreach ($this->pageImages as $pageImage) { 313 if (!$pageImage->getImage()->exists()) { 314 throw new ExceptionCombo("The image ({$pageImage->getImage()}) does not exist", $this->getCanonical()); 315 } 316 } 317 } 318 } 319 320 321 /** 322 * @throws ExceptionCombo 323 */ 324 public 325 function getDefaultImage(): ?Image 326 { 327 if (!PluginUtility::getConfValue(self::CONF_DISABLE_FIRST_IMAGE_AS_PAGE_IMAGE)) { 328 return $this->getFirstImage(); 329 } 330 return null; 331 } 332 333 /** 334 * @return ImageRaster|ImageSvg|null - the first image of the page 335 * @throws ExceptionCombo 336 */ 337 public function getFirstImage() 338 { 339 340 $store = $this->getReadStore(); 341 if (!($store instanceof MetadataDokuWikiStore)) { 342 return null; 343 } 344 /** 345 * Our first image metadata 346 * We can't overwrite the {@link \Doku_Renderer_metadata::$firstimage first image} 347 * We put it then in directly under the root 348 */ 349 $firstImageId = $store->getCurrentFromName(PageImages::FIRST_IMAGE_META_RELATION); 350 351 /** 352 * Dokuwiki first image metadata 353 */ 354 if (empty($firstImageId)) { 355 $relation = $store->getCurrentFromName('relation'); 356 if (!isset($relation[PageImages::FIRST_IMAGE_META_RELATION])) { 357 return null; 358 } 359 360 $firstImageId = $relation[PageImages::FIRST_IMAGE_META_RELATION]; 361 if (empty($firstImageId)) { 362 return null; 363 } 364 } 365 366 /** 367 * Image Id check 368 */ 369 if (media_isexternal($firstImageId)) { 370 return null; 371 } 372 return Image::createImageFromId($firstImageId); 373 374 } 375 376 377 function getChildrenClass(): array 378 { 379 return [PageImagePath::class, PageImageUsage::class]; 380 } 381 382 public function getUidClass(): string 383 { 384 return PageImagePath::class; 385 } 386 387 388 public function getDefaultValue(): ?array 389 { 390 391 $defaultImage = $this->getDefaultImage(); 392 $pageImagePath = null; 393 if ($defaultImage !== null) { 394 $pageImagePath = PageImagePath::createFromParent($this) 395 ->buildFromStoreValue($defaultImage->getPath()->toString()); 396 } 397 return [ 398 [ 399 PageImagePath::getPersistentName() => $pageImagePath, 400 PageImageUsage::getPersistentName() => PageImageUsage::createFromParent($this)->buildFromStoreValue([PageImageUsage::DEFAULT]) 401 ] 402 ]; 403 404 } 405 406 public static function getOldPersistentNames(): array 407 { 408 return [self::OLD_PROPERTY_NAME]; 409 } 410 411 412} 413