SproutCMS

This is the code documentation for the SproutCMS project

source of /sprout/Helpers/Lnk.php

  1. <?php
  2. /*
  3.  * Copyright (C) 2017 Karmabunny Pty Ltd.
  4.  *
  5.  * This file is a part of SproutCMS.
  6.  *
  7.  * SproutCMS is free software: you can redistribute it and/or modify it under the terms
  8.  * of the GNU General Public License as published by the Free Software Foundation, either
  9.  * version 2 of the License, or (at your option) any later version.
  10.  *
  11.  * For more information, visit <http://getsproutcms.com>.
  12.  */
  13.  
  14. namespace Sprout\Helpers;
  15.  
  16. use InvalidArgumentException;
  17.  
  18. use karmabunny\pdb\Exceptions\RowMissingException;
  19.  
  20. /**
  21.  * This is a system of portable, extensible link management.
  22.  *
  23.  * The system is based around the "link specification", which is a string.
  24.  * Link specifications should be stored in a TEXT field.
  25.  *
  26.  * These specs relate to classes which extend {@see LinkSpec}.
  27.  * The class name needs to start with "LinkSpec" too.
  28.  */
  29. class Lnk
  30. {
  31.  
  32. /**
  33.   * Some edit forms require additional javascript via the {@see needs} helper
  34.   * Load in all of these requirements for all LinkSpec classes
  35.   **/
  36. public static function editformNeeds()
  37. {
  38. $specs = Register::getLinkspecs();
  39. foreach ($specs as $class_name => $label) {
  40. $inst = new $class_name;
  41. $inst->loadNeeds();
  42. }
  43. }
  44.  
  45.  
  46. /**
  47.   * Output html for editing link specifications.
  48.   * This is designed for admin use.
  49.   *
  50.   * @param string $field_name The name to use for the field
  51.   * @param string $curr_spec Current spec data, for existing fields
  52.   * @param bool $required Is it a required field?
  53.   * @return string HTML
  54.   **/
  55. public static function editform($field_name, $curr_spec = null, $required = false)
  56. {
  57. self::editformNeeds();
  58.  
  59. $view = new View('sprout/components/lnk_editform');
  60. $view->field_name = $field_name;
  61. $view->curr_spec = $curr_spec;
  62. $view->required = $required;
  63. return $view->render();
  64. }
  65.  
  66.  
  67. /**
  68.   * For a given link specification, instance it's class
  69.   *
  70.   * @throw InvalidArgumentException If the link specification is invalid
  71.   * @throw InvalidArgumentException If the class is not found
  72.   * @param string $spec
  73.   * @return array [0] => instance, [1] => spec data
  74.   **/
  75. private static function instance($spec)
  76. {
  77. $spec = @json_decode($spec, true);
  78. if ($spec === null) {
  79. throw new InvalidArgumentException('Invalid link specification - parse error');
  80. }
  81.  
  82. if (!isset($spec['class']) or !isset($spec['data'])) {
  83. throw new InvalidArgumentException('Invalid link specification - missing fields');
  84. }
  85.  
  86. if (!class_exists($spec['class'])) {
  87. throw new InvalidArgumentException('Link specification refers to non-existant class');
  88. }
  89.  
  90. $specs = Register::getLinkspecs();
  91. if (!isset($specs[$spec['class']])) {
  92. throw new InvalidArgumentException('Link specification refers to non-registered class');
  93. }
  94.  
  95. $inst = new $spec['class'];
  96.  
  97. return array($inst, $spec['data'], $specs[$spec['class']]);
  98. }
  99.  
  100.  
  101. /**
  102.   * Convert a link specification into a URL.
  103.   *
  104.   * @param string $spec A link specification
  105.   * @return string Target URL
  106.   **/
  107. public static function url($spec)
  108. {
  109. list($inst, $data) = self::instance($spec);
  110. return $inst->getUrl($data);
  111. }
  112.  
  113.  
  114. /**
  115.   * Attempts to convert a link specification into a URL
  116.   *
  117.   * This differs in behaviour to `Lnk::url` as it will return null if the spec is
  118.   * empty, but *not* malformed; it still throws an InvalidArgumentException in that case.
  119.   * It will also return null if a RowMissingException is thrown by the link spec instance
  120.   * during processing.
  121.   *
  122.   * Helpful when you wish to avoid breaking pages when someone deletes the linked record, e.g. a blog post,
  123.   * without updating the corresponding link(s).
  124.   *
  125.   * @param string $spec A JSON link specification
  126.   * @return string|null The target URL or null if the spec is empty or if a RowMissingException
  127.   * is thrown during processing.
  128.   * @throws InvalidArgumentException If the link specification is malformed
  129.   */
  130. public static function tryUrl($spec)
  131. {
  132. if (empty($spec)) {
  133. return null;
  134. }
  135.  
  136. try {
  137. return self::url($spec);
  138. } catch (RowMissingException $exp) {
  139. return null;
  140. }
  141. }
  142.  
  143.  
  144. /**
  145.   * Return an opening A tag for a link specification.
  146.   *
  147.   * @param string $spec A link specification
  148.   * @param array $attributes Additional link attributes
  149.   * These take precedence over any default attributes
  150.   * @return string HTML for an opening A tag
  151.   **/
  152. public static function atag($spec, $attributes = array()) {
  153. list($inst, $data) = self::instance($spec);
  154.  
  155. if (! is_array($attributes)) $attributes = array();
  156. $attributes = array_filter(array_merge($inst->getAttrs($data), $attributes));
  157. ksort($attributes);
  158.  
  159. $html = '<a href="' . Enc::html($inst->getUrl($data)) . '"';
  160. foreach ($attributes as $name => $val) {
  161. $html .= ' ' . Enc::html($name) . '="' . Enc::html($val) . '"';
  162. }
  163. $html .= '>';
  164.  
  165. return $html;
  166. }
  167.  
  168.  
  169. /**
  170.   * Output the name of the type of the linkspec.
  171.   *
  172.   * @param string $spec A link specification
  173.   * @return string
  174.   **/
  175. public static function typename($spec)
  176. {
  177. list($inst, $data, $type_label) = self::instance($spec);
  178. return $type_label;
  179. }
  180.  
  181.  
  182. /**
  183.   * Check if the data supplied for a spec is valid.
  184.   *
  185.   * @param string $spec A link specification
  186.   * @return bool True if valid, false if invalid
  187.   **/
  188. public static function valid($spec)
  189. {
  190. list($inst, $data) = self::instance($spec);
  191. return $inst->isValid($data);
  192. }
  193.  
  194. }
  195.  
  196.