1<?php 2 3 4namespace ComboStrap; 5 6 7use ComboStrap\TagAttribute\Align; 8use ComboStrap\TagAttribute\Animation; 9use ComboStrap\TagAttribute\Shadow; 10use ComboStrap\Web\Url; 11use Doku_Renderer_metadata; 12use Doku_Renderer_xhtml; 13use renderer_plugin_combo_analytics; 14use syntax_plugin_combo_media; 15 16/** 17 * This class represents a media markup: 18 * - with a {@link MediaMarkup::getFetcher() fetcher} 19 * - and {@link MediaMarkup::getExtraMediaTagAttributes() tag/styling attributes} 20 * 21 * You can create it: 22 * * via a {@link MediaMarkup::createFromRef() Markup Ref} (The string ref in the document) 23 * * via a {@link MediaMarkup::createFromFetcher() Fetcher} 24 * * via a {@link MediaMarkup::createFromFetchUrl() Fetch Url} 25 * * via a {@link MediaMarkup::createFromCallStackArray() callstack array} of {@link syntax_plugin_combo_media::render()} 26 * * via a {@link MediaMarkup::createFromMarkup() string match} of {@link syntax_plugin_combo_media::handle()} 27 * 28 * 29 */ 30class MediaMarkup 31{ 32 33 /** 34 * No name as this is {{ --- }} 35 */ 36 public const TAG = "media"; 37 38 /** 39 * The dokuwiki type and mode name 40 * (ie call) 41 * * ie {@link MediaMarkup::EXTERNAL_MEDIA_CALL_NAME} 42 * or {@link MediaMarkup::INTERNAL_MEDIA_CALL_NAME} 43 * 44 * The dokuwiki type (internalmedia/externalmedia) 45 * 46 */ 47 public const MEDIA_DOKUWIKI_TYPE = 'dokuwiki_media_type'; 48 public const EXTERNAL_MEDIA_CALL_NAME = "externalmedia"; 49 public const INTERNAL_MEDIA_CALL_NAME = "internalmedia"; 50 51 /** 52 * Link value: 53 * * 'nolink' 54 * * 'direct': directly to the image 55 * * 'linkonly': show only a url 56 * * 'details': go to the details media viewer 57 * 58 * @var 59 */ 60 public const LINKING_KEY = 'linking'; 61 public const LINKING_DETAILS_VALUE = 'details'; 62 public const LINKING_DIRECT_VALUE = 'direct'; 63 /** 64 * Only used by Dokuwiki 65 * Contains the path and eventually an anchor 66 * never query parameters 67 */ 68 public const DOKUWIKI_SRC = "src"; 69 public const LINKING_LINKONLY_VALUE = "linkonly"; 70 public const LINKING_NOLINK_VALUE = 'nolink'; 71 /** 72 * Default image linking value 73 */ 74 public const CONF_DEFAULT_LINKING = "defaultImageLinking"; 75 76 const CANONICAL = "media"; 77 78 /** 79 * This attributes does not apply 80 * to a fetch (URL) 81 * They are only for the tag (img, svg, ...) 82 * or internal 83 */ 84 public const STYLE_ATTRIBUTES = [ 85 TagAttributes::TITLE_KEY, 86 Hover::ON_HOVER_ATTRIBUTE, 87 Animation::ON_VIEW_ATTRIBUTE, 88 Shadow::SHADOW_ATT, 89 Opacity::OPACITY_ATTRIBUTE, 90 TagAttributes::CLASS_KEY, 91 ]; 92 93 /** 94 * An attribute to set the class of the link if any 95 */ 96 public const LINK_CLASS_ATTRIBUTE = "link-class"; 97 public static string $MEDIA_QUERY_PARAMETER = "media"; 98 99 100 private ?string $align = null; 101 private ?string $label = null; 102 private ?MarkupRef $markupRef = null; 103 private ?string $linking = null; 104 private ?string $lazyLoadMethod = null; 105 private TagAttributes $extraMediaTagAttributes; 106 private ?string $linkingClass = null; 107 private IFetcher $fetcher; 108 private Url $fetchUrl; 109 110 private function __construct() 111 { 112 $this->extraMediaTagAttributes = TagAttributes::createEmpty(); 113 } 114 115 116 /** 117 * Private method use {@link MediaMarkup::createFromRef()} to create a media markup via a ref 118 * 119 * Set and parse a media wiki ref that you can found in the first part of a media markup 120 * 121 * @param string $markupRef 122 * @return MediaMarkup 123 * @throws ExceptionBadArgument 124 * @throws ExceptionBadSyntax 125 * @throws ExceptionNotFound 126 */ 127 private function setMarkupRef(string $markupRef): MediaMarkup 128 { 129 130 $markupRef = trim($markupRef); 131 $this->markupRef = MarkupRef::createMediaFromRef($markupRef); 132 133 $refUrl = $this->markupRef->getUrl(); 134 $this->setUrl($refUrl); 135 136 return $this; 137 } 138 139 /** 140 * @param $callStackArray 141 * @return MediaMarkup 142 * @throws ExceptionBadArgument 143 * @throws ExceptionBadSyntax 144 * @throws ExceptionNotFound 145 * @throws ExceptionNotExists 146 */ 147 public static function createFromCallStackArray($callStackArray): MediaMarkup 148 { 149 150 $tagAttributes = TagAttributes::createFromCallStackArray($callStackArray); 151 $ref = $tagAttributes->getValueAndRemoveIfPresent(MarkupRef::REF_ATTRIBUTE); 152 if ($ref === null) { 153 $ref = $tagAttributes->getValueAndRemoveIfPresent(MediaMarkup::DOKUWIKI_SRC); 154 if ($ref === null) { 155 throw new ExceptionBadArgument("The media reference was not found in the callstack array", self::CANONICAL); 156 } 157 } 158 return self::createFromRef($ref) 159 ->buildFromTagAttributes($tagAttributes); 160 161 162 } 163 164 /** 165 * @throws ExceptionBadArgument 166 * @throws ExceptionBadSyntax 167 * @throws ExceptionNotExists 168 * @throws ExceptionNotFound 169 * @throws ExceptionInternal 170 */ 171 public static function createFromFetchUrl(Url $fetchUrl): MediaMarkup 172 { 173 return (new MediaMarkup())->setUrl($fetchUrl); 174 } 175 176 public static function createFromFetcher(IFetcher $fetcher): MediaMarkup 177 { 178 return (new MediaMarkup()) 179 ->setFetcher($fetcher); 180 } 181 182 public static function renderSpecial(array $data, Doku_Renderer_xhtml $renderer) 183 { 184 185 $callStackArray = $data[PluginUtility::ATTRIBUTES]; 186 $display = $callStackArray[Display::DISPLAY] ?? null; 187 if ($display === Display::DISPLAY_NONE_VALUE) { 188 /** 189 * Used primarly to not show the featured images 190 * in the outline {@link Outline::toHtmlSectionOutlineCallsRecurse()} 191 * for item page 192 * But we keep the metadata to move them if any 193 */ 194 return false; 195 } 196 197 /** @var Doku_Renderer_xhtml $renderer */ 198 try { 199 $mediaMarkup = MediaMarkup::createFromCallStackArray($callStackArray); 200 } catch (ExceptionCompile $e) { 201 return $e->getMessage(); 202 } 203 204 205 if ( 206 $mediaMarkup->getInternalExternalType() === MediaMarkup::INTERNAL_MEDIA_CALL_NAME 207 ) { 208 try { 209 $isImage = $mediaMarkup->getFetcher()->getMime()->isImage(); 210 } catch (\Exception $e) { 211 $isImage = false; 212 } 213 if ($isImage) { 214 try { 215 return MediaLink::createFromMediaMarkup($mediaMarkup)->renderMediaTag(); 216 } catch (ExceptionCompile $e) { 217 if (PluginUtility::isDevOrTest()) { 218 throw new ExceptionRuntime("Media Rendering Error. {$e->getMessage()}", MediaLink::CANONICAL, 0, $e); 219 } else { 220 $errorClass = syntax_plugin_combo_media::SVG_RENDERING_ERROR_CLASS; 221 $message = "Media ({$mediaMarkup}). Error while rendering: {$e->getMessage()}"; 222 LogUtility::msg($message, LogUtility::LVL_MSG_ERROR, MediaLink::CANONICAL); 223 return "<span class=\"text-danger $errorClass\">" . hsc(trim($message)) . "</span>"; 224 225 } 226 } 227 } 228 229 } 230 231 232 /** 233 * This is not an local internal media image (a video or an url image) 234 * Dokuwiki takes over 235 */ 236 $mediaType = $mediaMarkup->getInternalExternalType(); 237 try { 238 $title = $mediaMarkup->getLabel(); 239 } catch (ExceptionNotFound $e) { 240 $title = null; 241 } 242 try { 243 $linking = $mediaMarkup->getLinking(); 244 } catch (ExceptionNotFound $e) { 245 $linking = null; 246 } 247 try { 248 $align = $mediaMarkup->getAlign(); 249 } catch (ExceptionNotFound $e) { 250 $align = null; 251 } 252 try { 253 /** 254 * We use the markup ref url 255 * because we don't support http/https (external) url 256 * And there is therefore no fetcher available 257 */ 258 $markupUrl = $mediaMarkup->getMarkupRef()->getUrl(); 259 260 } catch (ExceptionNotFound $e) { 261 // the 262 LogUtility::internalError("As the media markup is created from a markup in the syntax component, it should be available"); 263 return ""; 264 } 265 266 try { 267 $src = $mediaMarkup->getSrc(); 268 } catch (ExceptionNotFound $e) { 269 LogUtility::internalError("For an external markup, the src should not be empty", self::CANONICAL); 270 return ""; 271 } 272 try { 273 $isImage = FileSystems::getMime($markupUrl)->isImage(); 274 } catch (ExceptionNotFound $e) { 275 $isImage = false; 276 } 277 if ($isImage) { 278 /** 279 * We need to delete the 280 * wXh and other properties 281 * Dokuwiki does not accept it in its function 282 */ 283 try { 284 $src = Url::createEmpty() 285 ->setScheme($markupUrl->getScheme()) 286 ->setHost($markupUrl->getHost()) 287 ->setPath($markupUrl->getPath()) 288 ->toString(); 289 } catch (ExceptionNotFound $e) { 290 291 } 292 } 293 try { 294 $width = $markupUrl->getQueryPropertyValue(Dimension::WIDTH_KEY); 295 } catch 296 (ExceptionNotFound $e) { 297 $width = null; 298 } 299 try { 300 $height = $markupUrl->getQueryPropertyValue(Dimension::HEIGHT_KEY); 301 } catch (ExceptionNotFound $e) { 302 $height = null; 303 } 304 try { 305 $cache = $markupUrl->getQueryPropertyValue(IFetcherAbs::CACHE_KEY); 306 } catch (ExceptionNotFound $e) { 307 // Dokuwiki needs a value 308 // If their is no value it will output it without any value 309 // in the query string. 310 $cache = IFetcherAbs::CACHE_DEFAULT_VALUE; 311 } 312 switch ($mediaType) { 313 case MediaMarkup::INTERNAL_MEDIA_CALL_NAME: 314 return $renderer->internalmedia($src, $title, $align, $width, $height, $cache, $linking, true); 315 case MediaMarkup::EXTERNAL_MEDIA_CALL_NAME: 316 return $renderer->externalmedia($src, $title, $align, $width, $height, $cache, $linking, true); 317 default: 318 LogUtility::msg("The dokuwiki media type ($mediaType) is unknown"); 319 return ""; 320 } 321 } 322 323 324 /** 325 * Compliance: src in dokuwiki is the id and the anchor if any 326 * Dokuwiki does not understand other property and the reference metadata 327 * may not work if we send back the `ref` 328 * @throws ExceptionNotFound 329 */ 330 public function getSrc(): string 331 { 332 $internalExternalType = $this->getInternalExternalType(); 333 switch ($internalExternalType) { 334 case MediaMarkup::INTERNAL_MEDIA_CALL_NAME: 335 /** 336 * Absolute id because dokuwiki resolve a relatif id 337 * to the actual namespace 338 */ 339 $src = $this->getPath()->toAbsoluteId(); 340 try { 341 $src = "$src#{$this->markupRef->getUrl()->getFragment()}"; 342 } catch (ExceptionNotFound $e) { 343 // ok 344 } 345 return $src; 346 case MediaMarkup::EXTERNAL_MEDIA_CALL_NAME: 347 return $this->getMarkupRef()->getRef(); 348 default: 349 LogUtility::internalError("The internal/external type value ($internalExternalType) is unknown"); 350 return $this->getMarkupRef()->getRef(); 351 } 352 353 } 354 355 /** 356 * Media Type Needed by Dokuwiki 357 */ 358 public function getInternalExternalType(): string 359 { 360 try { 361 // if there is a path, this is internal 362 // if interwiki this, wiki id, ... 363 $this->markupRef->getPath(); 364 return self::INTERNAL_MEDIA_CALL_NAME; 365 } catch (ExceptionNotFound $e) { 366 return self::EXTERNAL_MEDIA_CALL_NAME; 367 } 368 369 } 370 371 372 /** 373 * @throws ExceptionBadSyntax 374 * @throws ExceptionBadArgument 375 * @throws ExceptionNotFound 376 */ 377 public static function createFromRef(string $markupRef): MediaMarkup 378 { 379 return (new MediaMarkup())->setMarkupRef($markupRef); 380 } 381 382 /** 383 * Keep track of the metadata 384 * @param array $data 385 * @param Doku_Renderer_metadata $renderer 386 * @return void 387 */ 388 public static function metadata(array $data, Doku_Renderer_metadata $renderer) 389 { 390 391 $tagAttributes = $data[PluginUtility::ATTRIBUTES]; 392 if ($tagAttributes === null) { 393 // error on handle 394 return; 395 } 396 syntax_plugin_combo_media::registerImageMeta($tagAttributes, $renderer); 397 398 } 399 400 /** 401 * Special pattern call 402 * @param array $data 403 * @param renderer_plugin_combo_analytics $renderer 404 * @return void 405 * @deprecated - for metadata but yeah ... 406 */ 407 public static function analytics(array $data, renderer_plugin_combo_analytics $renderer) 408 { 409 410 $tagAttributes = $data[PluginUtility::ATTRIBUTES]; 411 syntax_plugin_combo_media::updateStatistics($tagAttributes, $renderer); 412 413 } 414 415 416 /** 417 * @return Url - an url that has query property as a fetch url 418 * It permits to select the fetch class 419 * @deprecated use {@link MediaMarkup::getFetcher()}->getUrl instead 420 */ 421 public function getFetchUrl(): Url 422 { 423 return $this->getFetcher()->getFetchUrl(); 424 } 425 426 427 /** 428 * @param string $match - the match of the renderer 429 * @throws ExceptionBadSyntax - if no ref was found 430 * @throws ExceptionBadArgument 431 * @throws ExceptionNotFound|ExceptionNotExists 432 * @throws ExceptionInternal 433 */ 434 public static function createFromMarkup(string $match): MediaMarkup 435 { 436 437 $mediaMarkup = new MediaMarkup(); 438 439 /** 440 * * Delete the opening and closing character 441 * * create the url and description 442 */ 443 $match = preg_replace(array('/^{{/', '/}}$/u'), '', $match); 444 $parts = explode('|', $match, 2); 445 446 $ref = $parts[0]; 447 if ($ref === null) { 448 throw new ExceptionBadSyntax("No ref was found"); 449 } 450 $mediaMarkup->setMarkupRef($ref); 451 if (isset($parts[1])) { 452 $mediaMarkup->setLabel($parts[1]); 453 } 454 455 456 /** 457 * Media Alignment 458 */ 459 $rightAlign = (bool)preg_match('/^ /', $ref); 460 $leftAlign = (bool)preg_match('/ $/', $ref); 461 $align = null; 462 // Logic = what's that ;)... 463 if ($leftAlign & $rightAlign) { 464 $align = 'center'; 465 } else if ($rightAlign) { 466 $align = 'right'; 467 } else if ($leftAlign) { 468 $align = 'left'; 469 } 470 if ($align !== null) { 471 $mediaMarkup->setAlign($align); 472 } 473 474 return $mediaMarkup; 475 476 477 } 478 479 public function setAlign(string $align): MediaMarkup 480 { 481 $this->align = $align; 482 return $this; 483 } 484 485 public function setLabel(string $label): MediaMarkup 486 { 487 $this->label = $label; 488 return $this; 489 } 490 491 /** 492 * just FYI, not used 493 * 494 * Create an image from dokuwiki {@link Internallink internal call media attributes} 495 * 496 * Dokuwiki extracts already the width, height and align property 497 * @param array $callAttributes 498 * @return MediaMarkup 499 */ 500 public static function createFromIndexAttributes(array $callAttributes) 501 { 502 $src = $callAttributes[0]; 503 $title = $callAttributes[1]; 504 $align = $callAttributes[2]; 505 $width = $callAttributes[3]; 506 $height = $callAttributes[4]; 507 $cache = $callAttributes[5]; 508 $linking = $callAttributes[6]; 509 510 $ref = "$src?{$width}x$height&$cache"; 511 return (new MediaMarkup()) 512 ->setMarkupRef($ref) 513 ->setAlign($align) 514 ->setLabel($title) 515 ->setLinking($linking); 516 517 } 518 519 /** 520 * A function to set explicitly which array format 521 * is used in the returned data of a {@link SyntaxPlugin::handle()} 522 * (which ultimately is stored in the {@link CallStack) 523 * 524 * This is to make the difference with the {@link MediaLink::createFromIndexAttributes()} 525 * that is indexed by number (ie without property name) 526 * 527 * 528 * Return the array that is used in the {@link CallStack} 529 * 530 * @return array of key string and value 531 */ 532 public function toCallStackArray(): array 533 { 534 /** 535 * We store linking as attribute (to make it possible to change the linking by other plugin) 536 * (ie no linking in heading , ...) 537 */ 538 $attributes[MediaMarkup::LINKING_KEY] = $this->linking; 539 $attributes[MarkupRef::REF_ATTRIBUTE] = $this->markupRef->getRef(); 540 $attributes[Align::ALIGN_ATTRIBUTE] = $this->align; 541 $attributes[TagAttributes::TITLE_KEY] = $this->label; 542 return $attributes; 543 544 } 545 546 public function setLinking(string $linking): MediaMarkup 547 { 548 $this->linking = $linking; 549 return $this; 550 } 551 552 /** 553 * @throws ExceptionNotFound 554 */ 555 public function getLinking(): string 556 { 557 /** 558 * Linking 559 */ 560 $linking = $this->linking; 561 if ($linking !== null) { 562 return $linking; 563 } 564 throw new ExceptionNotFound("No linking set"); 565 566 567 } 568 569 /** 570 * Align on the url has precedence 571 * if present 572 * @throws ExceptionNotFound 573 */ 574 public function getAlign(): string 575 { 576 577 if ($this->align !== null) { 578 return $this->align; 579 } 580 throw new ExceptionNotFound("No align was specified"); 581 } 582 583 584 public function toTagAttributes() 585 { 586 587 588 /** 589 * The align attribute on an image parse 590 * is a float right 591 * ComboStrap does a difference between a block right and a float right 592 */ 593 try { 594 $align = $this->getAlign(); 595 if ($align === "right") { 596 $this->extraMediaTagAttributes->addComponentAttributeValue(FloatAttribute::FLOAT_KEY, "right"); 597 } else { 598 $this->extraMediaTagAttributes->addComponentAttributeValue(Align::ALIGN_ATTRIBUTE, $align); 599 } 600 } catch (ExceptionNotFound $e) { 601 // ok 602 } 603 604 return $this->extraMediaTagAttributes; 605 606 } 607 608 /** 609 * @throws ExceptionNotFound 610 */ 611 public function getLabel(): string 612 { 613 if (empty($this->label)) { 614 throw new ExceptionNotFound("No label specified"); 615 } 616 return $this->label; 617 } 618 619 public 620 function setLazyLoadMethod($false): MediaMarkup 621 { 622 $this->lazyLoadMethod = $false; 623 return $this; 624 } 625 626 /** 627 * @throws ExceptionNotFound 628 */ 629 public 630 function getLazyLoadMethod(): string 631 { 632 633 if ($this->lazyLoadMethod !== null) { 634 return $this->lazyLoadMethod; 635 } 636 throw new ExceptionNotFound("Lazy method is not specified"); 637 638 } 639 640 public 641 function getLazyLoadMethodOrDefault(): string 642 { 643 try { 644 return $this->getLazyLoadMethod(); 645 } catch (ExceptionNotFound $e) { 646 return LazyLoad::getDefault(); 647 } 648 649 } 650 651 652 public 653 static function isInternalMediaSyntax($text) 654 { 655 return preg_match(' / ' . syntax_plugin_combo_media::MEDIA_PATTERN . ' / msSi', $text); 656 } 657 658 659 public function isLazy(): bool 660 { 661 662 return $this->getLazyLoadMethodOrDefault() !== LazyLoad::LAZY_LOAD_METHOD_NONE_VALUE; 663 664 } 665 666 public function getExtraMediaTagAttributes(): TagAttributes 667 { 668 try { 669 $this->extraMediaTagAttributes->addComponentAttributeValue(Align::ALIGN_ATTRIBUTE, $this->getAlign()); 670 } catch (ExceptionNotFound $e) { 671 // ok 672 } 673 return $this->extraMediaTagAttributes; 674 } 675 676 677 public function __toString() 678 { 679 return $this->toMarkupSyntax(); 680 } 681 682 public function setLazyLoad(bool $true): MediaMarkup 683 { 684 if ($true) { 685 $this->lazyLoadMethod = LazyLoad::getDefault(); 686 } else { 687 $this->lazyLoadMethod = LazyLoad::LAZY_LOAD_METHOD_NONE_VALUE; 688 } 689 return $this; 690 } 691 692 /** 693 * Get and delete the attribute for the link 694 * (The rest is for the image) 695 */ 696 public 697 function getLinkingClass() 698 { 699 return $this->linkingClass; 700 } 701 702 /** 703 * @throws ExceptionNotFound 704 */ 705 public function getMarkupRef(): MarkupRef 706 { 707 if ($this->markupRef === null) { 708 throw new ExceptionNotFound("No markup, this media markup was not created from a markup"); 709 } 710 return $this->markupRef; 711 } 712 713 714 /** 715 * @param TagAttributes $tagAttributes - the attributes in a tag format 716 * @return $this 717 */ 718 public function buildFromTagAttributes(TagAttributes $tagAttributes): MediaMarkup 719 { 720 721 $linking = $tagAttributes->getValueAndRemoveIfPresent(self::LINKING_KEY); 722 if ($linking !== null) { 723 $this->setLinking($linking); 724 } 725 $label = $tagAttributes->getValueAndRemoveIfPresent(TagAttributes::TITLE_KEY); 726 if ($label !== null) { 727 $this->setLabel($label); 728 } 729 $align = $tagAttributes->getValueAndRemoveIfPresent(Align::ALIGN_ATTRIBUTE); 730 if ($align !== null) { 731 $this->setAlign($align); 732 } 733 $lazy = $tagAttributes->getValueAndRemoveIfPresent(LazyLoad::LAZY_LOAD_METHOD); 734 if ($lazy !== null) { 735 $this->setLazyLoadMethod($lazy); 736 } 737 738 /** 739 * dokuwiki attribute 740 */ 741 if (isset($this->fetchUrl)) { 742 $width = $tagAttributes->getValueAndRemoveIfPresent(Dimension::WIDTH_KEY); 743 if ($width !== null) { 744 $this->fetchUrl->addQueryParameterIfNotPresent(Dimension::WIDTH_KEY, $width); 745 } 746 $height = $tagAttributes->getValueAndRemoveIfPresent(Dimension::HEIGHT_KEY); 747 if ($height !== null) { 748 $this->fetchUrl->addQueryParameterIfNotPresent(Dimension::HEIGHT_KEY, $height); 749 } 750 $ratio = $tagAttributes->getValueAndRemoveIfPresent(Dimension::RATIO_ATTRIBUTE); 751 if ($ratio !== null) { 752 $this->fetchUrl->addQueryParameterIfNotPresent(Dimension::RATIO_ATTRIBUTE, $ratio); 753 } 754 } 755 756 foreach ($tagAttributes->getComponentAttributes() as $key => $value) { 757 $this->extraMediaTagAttributes->addComponentAttributeValue($key, $value); 758 } 759 760 foreach ($tagAttributes->getStyleDeclarations() as $key => $value) { 761 $this->extraMediaTagAttributes->addStyleDeclarationIfNotSet($key, $value); 762 } 763 764 return $this; 765 } 766 767 /** 768 * @throws ExceptionBadArgument 769 * @throws ExceptionBadSyntax 770 * @throws ExceptionNotExists 771 * @throws ExceptionNotFound 772 */ 773 public function toHtml(): string 774 { 775 return MediaLink::createFromMediaMarkup($this) 776 ->renderMediaTag(); 777 } 778 779 /** 780 * @throws ExceptionBadSyntax 781 * @throws ExceptionBadArgument 782 * @throws ExceptionNotExists 783 * @throws ExceptionNotFound 784 */ 785 public function getMediaLink() 786 { 787 return MediaLink::createFromMediaMarkup($this); 788 } 789 790 private 791 function setLinkingClass($value): MediaMarkup 792 { 793 $this->linkingClass = $value; 794 return $this; 795 } 796 797 /** 798 * @return string the wiki syntax 799 */ 800 public function toMarkupSyntax(): string 801 { 802 $descriptionPart = ""; 803 try { 804 $descriptionPart = "|" . $this->getLabel(); 805 } catch (ExceptionNotFound $e) { 806 // ok 807 } 808 try { 809 $ref = $this->getRef(); 810 } catch (ExceptionNotFound $e) { 811 $ref = $this->getFetchUrl()->toString(); 812 } 813 return '{{' . $ref . $descriptionPart . '}}'; 814 } 815 816 /** 817 * 818 * Private method use {@link MediaMarkup::createFromFetchUrl()} to create a media markup via a Url 819 * 820 * @throws ExceptionNotFound 821 */ 822 private function setUrl(Url $fetchUrl): MediaMarkup 823 { 824 825 /** 826 * Tag Attributes 827 */ 828 try { 829 $this->align = $fetchUrl->getQueryPropertyValueAndRemoveIfPresent(Align::ALIGN_ATTRIBUTE); 830 } catch (ExceptionNotFound $e) { 831 // ok 832 } 833 try { 834 $this->linking = $fetchUrl->getQueryPropertyValueAndRemoveIfPresent(self::LINKING_KEY); 835 } catch (ExceptionNotFound $e) { 836 // ok 837 } 838 try { 839 $this->lazyLoadMethod = $fetchUrl->getQueryPropertyValueAndRemoveIfPresent(LazyLoad::LAZY_LOAD_METHOD); 840 } catch (ExceptionNotFound $e) { 841 // ok 842 } 843 try { 844 $this->linkingClass = $fetchUrl->getQueryPropertyValueAndRemoveIfPresent(self::LINK_CLASS_ATTRIBUTE); 845 } catch (ExceptionNotFound $e) { 846 // ok 847 } 848 849 foreach (self::STYLE_ATTRIBUTES as $nonUrlAttribute) { 850 try { 851 $value = $fetchUrl->getQueryPropertyValueAndRemoveIfPresent($nonUrlAttribute); 852 $this->extraMediaTagAttributes->addComponentAttributeValue($nonUrlAttribute, $value); 853 } catch (ExceptionNotFound $e) { 854 // ok 855 } 856 } 857 858 $this->fetchUrl = $fetchUrl; 859 return $this; 860 } 861 862 /** 863 * @throws ExceptionNotFound 864 */ 865 private function getRef(): string 866 { 867 if ($this->markupRef === null) { 868 throw new ExceptionNotFound("No ref was specified"); 869 } 870 return $this->markupRef->getRef(); 871 } 872 873 /** 874 * @throws ExceptionNotFound - if this markup does not have a path origin 875 * @deprecated use the {@link self::getFetcher()} instead 876 * A media may be generated (ie {@link FetcherVignette} 877 * therefore the path may be not present 878 * 879 * If you want to known the mime use {@link self::getFetcher()} then {@link IFetcher::getMime()} 880 */ 881 public function getPath(): WikiPath 882 { 883 try { 884 885 return $this->getMarkupRef()->getPath(); 886 887 } catch (ExceptionNotFound $e) { 888 889 if ($this->fetcher instanceof IFetcherSource) { 890 return $this->fetcher->getSourcePath(); 891 } 892 throw $e; 893 894 } 895 } 896 897 /** 898 * Private method use {@link MediaMarkup::createFromFetcher()} to create a media markup via a Fetcher 899 * @param IFetcher $fetcher 900 * @return MediaMarkup 901 */ 902 private function setFetcher(IFetcher $fetcher): MediaMarkup 903 { 904 $this->fetcher = $fetcher; 905 return $this; 906 } 907 908 909 /** 910 * @return IFetcher 911 */ 912 public function getFetcher(): IFetcher 913 { 914 if (!isset($this->fetcher)) { 915 if (!isset($this->fetchUrl)) { 916 throw new ExceptionRuntimeInternal("No fetcher or url was set"); 917 } 918 /** 919 * Fetcher is build later 920 * because for a raster image 921 * actually, we can't built it 922 * if the file does not exists. 923 * It will throw an error immediatly and we may want not. 924 * For resources, we want to build the url even if the image does not exists. 925 */ 926 try { 927 $this->fetcher = FetcherSystem::createPathFetcherFromUrl($this->fetchUrl); 928 } catch (ExceptionBadArgument|ExceptionInternal|ExceptionNotFound $e) { 929 try { 930 // we don't support http fetch 931 if (!($this->getMarkupRef()->getSchemeType() === MarkupRef::WEB_URI)) { 932 throw ExceptionRuntimeInternal::withMessageAndError("we don't support http fetch", $e); 933 } 934 } catch (ExceptionNotFound $e) { 935 // ok no markup ref 936 } 937 } 938 } 939 return $this->fetcher; 940 } 941 942 943} 944