4
0

Share.php 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341
  1. <?php
  2. /**
  3. * Manage the sharing options in FreshRSS.
  4. */
  5. class FreshRSS_Share {
  6. /**
  7. * The list of available sharing options.
  8. * @var array<string,FreshRSS_Share>
  9. */
  10. private static array $list_sharing = [];
  11. /**
  12. * Register a new sharing option.
  13. * @param array{'type':string,'url':string,'transform'?:array<callable>|array<string,array<callable>>,'field'?:string,'help'?:string,'form'?:'simple'|'advanced',
  14. * 'method'?:'GET'|'POST','HTMLtag'?:'button','deprecated'?:bool} $share_options is an array defining the share option.
  15. */
  16. public static function register(array $share_options): void {
  17. $type = $share_options['type'];
  18. if (isset(self::$list_sharing[$type])) {
  19. return;
  20. }
  21. self::$list_sharing[$type] = new FreshRSS_Share(
  22. $type,
  23. $share_options['url'],
  24. $share_options['transform'] ?? [],
  25. $share_options['form'] ?? 'simple',
  26. $share_options['help'] ?? '',
  27. $share_options['method'] ?? 'GET',
  28. $share_options['field'] ?? null,
  29. $share_options['HTMLtag'] ?? null,
  30. $share_options['deprecated'] ?? false
  31. );
  32. }
  33. /**
  34. * Register sharing options in a file.
  35. * @param string $filename the name of the file to load.
  36. */
  37. public static function load(string $filename): void {
  38. $shares_from_file = @include($filename);
  39. if (!is_array($shares_from_file)) {
  40. $shares_from_file = [];
  41. }
  42. foreach ($shares_from_file as $share_type => $share_options) {
  43. $share_options['type'] = $share_type;
  44. self::register($share_options);
  45. }
  46. uasort(self::$list_sharing, static function (FreshRSS_Share $a, FreshRSS_Share $b) {
  47. return strcasecmp($a->name() ?? '', $b->name() ?? '');
  48. });
  49. }
  50. /**
  51. * Return the list of sharing options.
  52. * @return array<string,FreshRSS_Share>
  53. */
  54. public static function enum(): array {
  55. return self::$list_sharing;
  56. }
  57. /**
  58. * @param string $type the share type, null if $type is not registered.
  59. * @return FreshRSS_Share|null object related to the given type.
  60. */
  61. public static function get(string $type): ?FreshRSS_Share {
  62. return self::$list_sharing[$type] ?? null;
  63. }
  64. private string $type;
  65. private string $name;
  66. private string $url_transform;
  67. /** @var array<callable>|array<string,array<callable>> */
  68. private array $transforms;
  69. /**
  70. * @phpstan-var 'simple'|'advanced'
  71. */
  72. private string $form_type;
  73. private string $help_url;
  74. private ?string $custom_name = null;
  75. private ?string $base_url = null;
  76. private ?string $id = null;
  77. private ?string $title = null;
  78. private ?string $link = null;
  79. private bool $isDeprecated;
  80. /**
  81. * @phpstan-var 'GET'|'POST'
  82. */
  83. private string $method;
  84. private ?string $field;
  85. /**
  86. * @phpstan-var 'button'|null
  87. */
  88. private ?string $HTMLtag;
  89. /**
  90. * Create a FreshRSS_Share object.
  91. * @param string $type is a unique string defining the kind of share option.
  92. * @param string $url_transform defines the url format to use in order to share.
  93. * @param array<callable>|array<string,array<callable>> $transforms is an array of transformations to apply on link and title.
  94. * @param 'simple'|'advanced' $form_type defines which form we have to use to complete. "simple"
  95. * is typically for a centralized service while "advanced" is for
  96. * decentralized ones.
  97. * @param string $help_url is an optional url to give help on this option.
  98. * @param 'GET'|'POST' $method defines the sharing method (GET or POST)
  99. * @param string|null $field
  100. * @param 'button'|null $HTMLtag
  101. * @param bool $isDeprecated
  102. */
  103. private function __construct(string $type, string $url_transform, array $transforms, string $form_type,
  104. string $help_url, string $method, ?string $field, ?string $HTMLtag, bool $isDeprecated = false) {
  105. $this->type = $type;
  106. $this->name = _t('gen.share.' . $type);
  107. $this->url_transform = $url_transform;
  108. $this->help_url = $help_url;
  109. $this->HTMLtag = $HTMLtag;
  110. $this->isDeprecated = $isDeprecated;
  111. $this->transforms = $transforms;
  112. if (!in_array($form_type, ['simple', 'advanced'], true)) {
  113. $form_type = 'simple';
  114. }
  115. $this->form_type = $form_type;
  116. if (!in_array($method, ['GET', 'POST'], true)) {
  117. $method = 'GET';
  118. }
  119. $this->method = $method;
  120. $this->field = $field;
  121. }
  122. /**
  123. * Update a FreshRSS_Share object with information from an array.
  124. * @param array<string,string> $options is a list of information to update where keys should be
  125. * in this list: name, url, id, title, link.
  126. */
  127. public function update(array $options): void {
  128. foreach ($options as $key => $value) {
  129. switch ($key) {
  130. case 'name':
  131. $this->custom_name = $value;
  132. break;
  133. case 'url':
  134. $this->base_url = $value;
  135. break;
  136. case 'id':
  137. $this->id = $value;
  138. break;
  139. case 'title':
  140. $this->title = $value;
  141. break;
  142. case 'link':
  143. $this->link = $value;
  144. break;
  145. case 'method':
  146. $this->method = strcasecmp($value, 'POST') === 0 ? 'POST' : 'GET';
  147. break;
  148. case 'field';
  149. $this->field = $value;
  150. break;
  151. }
  152. }
  153. }
  154. /**
  155. * Return the current type of the share option.
  156. */
  157. public function type(): string {
  158. return $this->type;
  159. }
  160. /**
  161. * Return the current method of the share option.
  162. * @return 'GET'|'POST'
  163. */
  164. public function method(): string {
  165. return $this->method;
  166. }
  167. /**
  168. * Return the current field of the share option. It’s null for shares
  169. * using the GET method.
  170. */
  171. public function field(): ?string {
  172. return $this->field;
  173. }
  174. /**
  175. * Return the current form type of the share option.
  176. * @return 'simple'|'advanced'
  177. */
  178. public function formType(): string {
  179. return $this->form_type;
  180. }
  181. /**
  182. * Return the current help url of the share option.
  183. */
  184. public function help(): string {
  185. return $this->help_url;
  186. }
  187. /**
  188. * Return the custom type of HTML tag of the share option, null for default.
  189. * @return 'button'|null
  190. */
  191. public function HTMLtag(): ?string {
  192. return $this->HTMLtag;
  193. }
  194. /**
  195. * Return the current name of the share option.
  196. */
  197. public function name(bool $real = false): ?string {
  198. if ($real || empty($this->custom_name)) {
  199. return $this->name;
  200. } else {
  201. return $this->custom_name;
  202. }
  203. }
  204. /**
  205. * Return the current base url of the share option.
  206. */
  207. public function baseUrl(): string {
  208. return $this->base_url ?? '';
  209. }
  210. /**
  211. * Return the deprecated status of the share option.
  212. */
  213. public function isDeprecated(): bool {
  214. return $this->isDeprecated;
  215. }
  216. /**
  217. * Return the current url by merging url_transform and base_url.
  218. */
  219. public function url(): string {
  220. $matches = [
  221. '~ID~',
  222. '~URL~',
  223. '~TITLE~',
  224. '~LINK~',
  225. ];
  226. $replaces = [
  227. $this->id(),
  228. $this->base_url,
  229. $this->title(),
  230. $this->link(),
  231. ];
  232. return str_replace($matches, $replaces, $this->url_transform);
  233. }
  234. /**
  235. * Return the id.
  236. * @param bool $raw true if we should get the id without transformations.
  237. */
  238. public function id(bool $raw = false): ?string {
  239. if ($raw) {
  240. return $this->id;
  241. }
  242. if ($this->id === null) {
  243. return null;
  244. }
  245. return self::transform($this->id, $this->getTransform('id'));
  246. }
  247. /**
  248. * Return the title.
  249. * @param bool $raw true if we should get the title without transformations.
  250. */
  251. public function title(bool $raw = false): string {
  252. if ($raw) {
  253. return $this->title ?? '';
  254. }
  255. if ($this->title === null) {
  256. return '';
  257. }
  258. return self::transform($this->title, $this->getTransform('title'));
  259. }
  260. /**
  261. * Return the link.
  262. * @param bool $raw true if we should get the link without transformations.
  263. */
  264. public function link(bool $raw = false): string {
  265. if ($raw) {
  266. return $this->link ?? '';
  267. }
  268. if ($this->link === null) {
  269. return '';
  270. }
  271. return self::transform($this->link, $this->getTransform('link'));
  272. }
  273. /**
  274. * Transform a data with the given functions.
  275. * @param string $data the data to transform.
  276. * @param array<callable> $transform an array containing a list of functions to apply.
  277. * @return string the transformed data.
  278. */
  279. private static function transform(string $data, array $transform): string {
  280. if (empty($transform)) {
  281. return $data;
  282. }
  283. foreach ($transform as $action) {
  284. $data = call_user_func($action, $data);
  285. }
  286. return $data;
  287. }
  288. /**
  289. * Get the list of transformations for the given attribute.
  290. * @param string $attr the attribute of which we want the transformations.
  291. * @return array<callable> containing a list of transformations to apply.
  292. */
  293. private function getTransform(string $attr): array {
  294. if (array_key_exists($attr, $this->transforms)) {
  295. $candidates = is_array($this->transforms[$attr]) ? $this->transforms[$attr] : [];
  296. } else {
  297. $candidates = $this->transforms;
  298. }
  299. $transforms = [];
  300. foreach ($candidates as $transform) {
  301. if (is_callable($transform)) {
  302. $transforms[] = $transform;
  303. }
  304. }
  305. return $transforms;
  306. }
  307. }