mirror of
https://github.com/FreshRSS/FreshRSS.git
synced 2025-12-23 21:47:44 -05:00
1. `include`, `include_once`, `require` and `require_once` are expressions not functions, parentheses are not necessary. 2. to move up the directory tree, it's better to use the `dirname` function instead of relying on `/..`.
336 lines
8.5 KiB
PHP
336 lines
8.5 KiB
PHP
<?php
|
||
declare(strict_types=1);
|
||
|
||
/**
|
||
* Manage the sharing options in FreshRSS.
|
||
*/
|
||
class FreshRSS_Share {
|
||
/**
|
||
* The list of available sharing options.
|
||
* @var array<string,FreshRSS_Share>
|
||
*/
|
||
private static array $list_sharing = [];
|
||
|
||
/**
|
||
* Register a new sharing option.
|
||
* @param array{type:string,url:string,transform?:array<callable>|array<string,array<callable>>,field?:string,help?:string,form?:'simple'|'advanced',
|
||
* method?:'GET'|'POST',HTMLtag?:'button',deprecated?:bool} $share_options is an array defining the share option.
|
||
*/
|
||
public static function register(array $share_options): void {
|
||
$type = $share_options['type'];
|
||
if (isset(self::$list_sharing[$type])) {
|
||
return;
|
||
}
|
||
|
||
self::$list_sharing[$type] = new FreshRSS_Share(
|
||
$type,
|
||
$share_options['url'],
|
||
$share_options['transform'] ?? [],
|
||
$share_options['form'] ?? 'simple',
|
||
$share_options['help'] ?? '',
|
||
$share_options['method'] ?? 'GET',
|
||
$share_options['field'] ?? null,
|
||
$share_options['HTMLtag'] ?? null,
|
||
$share_options['deprecated'] ?? false
|
||
);
|
||
}
|
||
|
||
/**
|
||
* Register sharing options in a file.
|
||
* @param string $filename the name of the file to load.
|
||
*/
|
||
public static function load(string $filename): void {
|
||
$shares_from_file = @include $filename;
|
||
if (!is_array($shares_from_file)) {
|
||
$shares_from_file = [];
|
||
}
|
||
|
||
foreach ($shares_from_file as $share_type => $share_options) {
|
||
if (!is_array($share_options)) {
|
||
continue;
|
||
}
|
||
$share_options['type'] = $share_type;
|
||
/** @var array{type:string,url:string,transform?:array<callable>|array<string,array<callable>>,field?:string,help?:string,form?:'simple'|'advanced',
|
||
* method?:'GET'|'POST',HTMLtag?:'button',deprecated?:bool} $share_options */
|
||
self::register($share_options);
|
||
}
|
||
|
||
uasort(self::$list_sharing, static fn(FreshRSS_Share $a, FreshRSS_Share $b) => strcasecmp($a->name() ?? '', $b->name() ?? ''));
|
||
}
|
||
|
||
/**
|
||
* Return the list of sharing options.
|
||
* @return array<string,FreshRSS_Share>
|
||
*/
|
||
public static function enum(): array {
|
||
return self::$list_sharing;
|
||
}
|
||
|
||
/**
|
||
* @param string $type the share type, null if $type is not registered.
|
||
* @return FreshRSS_Share|null object related to the given type.
|
||
*/
|
||
public static function get(string $type): ?FreshRSS_Share {
|
||
return self::$list_sharing[$type] ?? null;
|
||
}
|
||
private readonly string $name;
|
||
/**
|
||
* @phpstan-var 'simple'|'advanced'
|
||
*/
|
||
private readonly string $form_type;
|
||
private ?string $custom_name = null;
|
||
private ?string $base_url = null;
|
||
private ?string $id = null;
|
||
private ?string $title = null;
|
||
private ?string $link = null;
|
||
/**
|
||
* @phpstan-var 'GET'|'POST'
|
||
*/
|
||
private string $method;
|
||
|
||
/**
|
||
* Create a FreshRSS_Share object.
|
||
* @param string $type is a unique string defining the kind of share option.
|
||
* @param string $url_transform defines the url format to use in order to share.
|
||
* @param array<callable>|array<string,array<callable>> $transforms is an array of transformations to apply on link and title.
|
||
* @param 'simple'|'advanced' $form_type defines which form we have to use to complete. "simple"
|
||
* is typically for a centralized service while "advanced" is for
|
||
* decentralized ones.
|
||
* @param string $help_url is an optional url to give help on this option.
|
||
* @param 'GET'|'POST' $method defines the sharing method (GET or POST)
|
||
* @param 'button'|null $HTMLtag
|
||
*/
|
||
private function __construct(
|
||
private readonly string $type,
|
||
private readonly string $url_transform,
|
||
private array $transforms,
|
||
string $form_type,
|
||
private readonly string $help_url,
|
||
string $method,
|
||
private ?string $field,
|
||
private readonly ?string $HTMLtag,
|
||
private readonly bool $isDeprecated = false
|
||
) {
|
||
$this->name = _t('gen.share.' . $this->type);
|
||
|
||
if (!in_array($form_type, ['simple', 'advanced'], true)) {
|
||
$form_type = 'simple';
|
||
}
|
||
$this->form_type = $form_type;
|
||
if (!in_array($method, ['GET', 'POST'], true)) {
|
||
$method = 'GET';
|
||
}
|
||
$this->method = $method;
|
||
}
|
||
|
||
/**
|
||
* Update a FreshRSS_Share object with information from an array.
|
||
* @param array<string,string> $options is a list of information to update where keys should be
|
||
* in this list: name, url, id, title, link.
|
||
*/
|
||
public function update(array $options): void {
|
||
foreach ($options as $key => $value) {
|
||
switch ($key) {
|
||
case 'name':
|
||
$this->custom_name = $value;
|
||
break;
|
||
case 'url':
|
||
$this->base_url = $value;
|
||
break;
|
||
case 'id':
|
||
$this->id = $value;
|
||
break;
|
||
case 'title':
|
||
$this->title = $value;
|
||
break;
|
||
case 'link':
|
||
$this->link = $value;
|
||
break;
|
||
case 'method':
|
||
$this->method = strcasecmp($value, 'POST') === 0 ? 'POST' : 'GET';
|
||
break;
|
||
case 'field':
|
||
$this->field = $value;
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Return the current type of the share option.
|
||
*/
|
||
public function type(): string {
|
||
return $this->type;
|
||
}
|
||
|
||
/**
|
||
* Return the current method of the share option.
|
||
* @return 'GET'|'POST'
|
||
*/
|
||
public function method(): string {
|
||
return $this->method;
|
||
}
|
||
|
||
/**
|
||
* Return the current field of the share option. It’s null for shares
|
||
* using the GET method.
|
||
*/
|
||
public function field(): ?string {
|
||
return $this->field;
|
||
}
|
||
|
||
/**
|
||
* Return the current form type of the share option.
|
||
* @return 'simple'|'advanced'
|
||
*/
|
||
public function formType(): string {
|
||
return $this->form_type;
|
||
}
|
||
|
||
/**
|
||
* Return the current help url of the share option.
|
||
*/
|
||
public function help(): string {
|
||
return $this->help_url;
|
||
}
|
||
|
||
/**
|
||
* Return the custom type of HTML tag of the share option, null for default.
|
||
* @return 'button'|null
|
||
*/
|
||
public function HTMLtag(): ?string {
|
||
return $this->HTMLtag;
|
||
}
|
||
|
||
/**
|
||
* Return the current name of the share option.
|
||
*/
|
||
public function name(bool $real = false): ?string {
|
||
if ($real || empty($this->custom_name)) {
|
||
return $this->name;
|
||
} else {
|
||
return $this->custom_name;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Return the current base url of the share option.
|
||
*/
|
||
public function baseUrl(): string {
|
||
return $this->base_url ?? '';
|
||
}
|
||
|
||
/**
|
||
* Return the deprecated status of the share option.
|
||
*/
|
||
public function isDeprecated(): bool {
|
||
return $this->isDeprecated;
|
||
}
|
||
|
||
/**
|
||
* Return the current url by merging url_transform and base_url.
|
||
*/
|
||
public function url(): string {
|
||
$matches = [
|
||
'~ID~',
|
||
'~URL~',
|
||
'~TITLE~',
|
||
'~LINK~',
|
||
];
|
||
$replaces = [
|
||
$this->id() ?? '',
|
||
$this->base_url ?? '',
|
||
$this->title(),
|
||
$this->link(),
|
||
];
|
||
return str_replace($matches, $replaces, $this->url_transform);
|
||
}
|
||
|
||
/**
|
||
* Return the id.
|
||
* @param bool $raw true if we should get the id without transformations.
|
||
*/
|
||
public function id(bool $raw = false): ?string {
|
||
if ($raw) {
|
||
return $this->id;
|
||
}
|
||
|
||
if ($this->id === null) {
|
||
return null;
|
||
}
|
||
return self::transform($this->id, $this->getTransform('id'));
|
||
}
|
||
|
||
/**
|
||
* Return the title.
|
||
* @param bool $raw true if we should get the title without transformations.
|
||
*/
|
||
public function title(bool $raw = false): string {
|
||
if ($raw) {
|
||
return $this->title ?? '';
|
||
}
|
||
|
||
if ($this->title === null) {
|
||
return '';
|
||
}
|
||
return self::transform($this->title, $this->getTransform('title'));
|
||
}
|
||
|
||
/**
|
||
* Return the link.
|
||
* @param bool $raw true if we should get the link without transformations.
|
||
*/
|
||
public function link(bool $raw = false): string {
|
||
if ($raw) {
|
||
return $this->link ?? '';
|
||
}
|
||
if ($this->link === null) {
|
||
return '';
|
||
}
|
||
|
||
return self::transform($this->link, $this->getTransform('link'));
|
||
}
|
||
|
||
/**
|
||
* Transform a data with the given functions.
|
||
* @param string $data the data to transform.
|
||
* @param array<callable> $transform an array containing a list of functions to apply.
|
||
* @return string the transformed data.
|
||
*/
|
||
private static function transform(string $data, array $transform): string {
|
||
if (empty($transform)) {
|
||
return $data;
|
||
}
|
||
|
||
foreach ($transform as $action) {
|
||
$return = call_user_func($action, $data);
|
||
if (is_string($return)) {
|
||
$data = $return;
|
||
}
|
||
}
|
||
|
||
return $data;
|
||
}
|
||
|
||
/**
|
||
* Get the list of transformations for the given attribute.
|
||
* @param string $attr the attribute of which we want the transformations.
|
||
* @return list<callable> containing a list of transformations to apply.
|
||
*/
|
||
private function getTransform(string $attr): array {
|
||
if (array_key_exists($attr, $this->transforms)) {
|
||
$candidates = is_array($this->transforms[$attr]) ? $this->transforms[$attr] : [];
|
||
} else {
|
||
$candidates = $this->transforms;
|
||
}
|
||
|
||
$transforms = [];
|
||
foreach ($candidates as $transform) {
|
||
if (is_callable($transform)) {
|
||
$transforms[] = $transform;
|
||
}
|
||
}
|
||
return $transforms;
|
||
}
|
||
}
|