<?php
namespace StartDir;
class LinkGenerator
{
/**
* @var array<string, array<string, string>>
*/
private array $templates = [];
public function __construct(array $defaultTemplates = [])
{
$this->templates = $defaultTemplates;
}
public function addDefaults(){
//following & followers
//mastodon
$this->addTemplate(
'misskey',
'following',
'https://{instance}/@{username}/following'
);
$this->addTemplate(
'misskey',
'followers',
'https://{instance}/@{username}/followers'
);
//mastodon
$this->addTemplate(
'mastodon',
'following',
'https://{instance}/@{username}/following'
);
$this->addTemplate(
'mastodon',
'followers',
'https://{instance}/@{username}/followers'
);
//hometown
$this->addTemplate(
'hometown',
'following',
'https://{instance}/@{username}/following'
);
$this->addTemplate(
'hometown',
'followers',
'https://{instance}/@{username}/followers'
);
//friendica
$this->addTemplate(
'friendica',
'following',
'https://{instance}/profile/{username}/contacts/following'
);
$this->addTemplate(
'friendica',
'followers',
'https://{instance}/profile/{username}/contacts/followers'
);
// search
$this->addTemplate(
'elgg',
'search',
'https://{instance}/search?q={q}'
);
$this->addTemplate(
'flohmarkt',
'search',
'https://{instance}/search?q={q}'
);
/*
$this->addTemplate(
'ecko',
'search',
'https://{instance}/search?q={q}'
);
$this->addTemplate(
'fedibird',
'search',
'https://{instance}/search?q={q}'
);
*/
$this->addTemplate(
'hometown',
'search',
'https://{instance}/search?q={q}'
);
$this->addTemplate(
'mastodon',
'search',
'https://{instance}/search?q={q}'
);
$this->addTemplate(
'friendica',
'search',
'https://{instance}/search?q={q}'
);
$this->addTemplate(
'wordpress',
'search',
'https://{instance}/?s={s}'
);
$this->addTemplate(
'peertube',
'search',
'https://{instance}/search?search={search}'
);
}
public function templateExists(string $software, string $module): bool
{
$software = strtolower($software);
return isset($this->templates[$software][$module])
&& is_string($this->templates[$software][$module])
&& $this->templates[$software][$module] !== '';
}
public function addTemplate(
string $software,
string $modul,
string $template
): void {
$this->templates[strtolower($software)][$modul] = $template;
}
public function generateLink(
string $instance,
string $software,
string $modul = 'search',
array $params = []
): string {
$software = strtolower($software);
if (!isset($this->templates[$software][$modul])) {
throw new \InvalidArgumentException(
sprintf(
'Kein Template f?r Modul "%s" in Software "%s" definiert.',
$modul,
$software
)
);
}
$template = $this->templates[$software][$modul];
$replacements = [
'{instance}' => rawurlencode($instance),
];
foreach ($params as $key => $value) {
$replacements['{' . $key . '}'] = rawurlencode($value);
}
$result = strtr($template, $replacements);
if (preg_match('/\{[a-zA-Z0-9_]+\}/', $result)) {
throw new \RuntimeException(
'Nicht ersetzte Platzhalter im Template vorhanden: ' . $result
);
}
return $result;
}
public function getFormHtml(
string $instance,
string $software,
string $modul = 'search',
string $method = 'GET',
array $defaultValues = [],
array $formAttributes = []
): string {
$software = strtolower($software);
if (!isset($this->templates[$software][$modul])) {
throw new \InvalidArgumentException(
sprintf(
'Kein Template f?r Modul "%s" in Software "%s" definiert.',
$modul,
$software
)
);
}
$template = $this->templates[$software][$modul];
// --- Template vorbereiten (nur {instance} ersetzen) ---
$preparedUrl = str_replace(
'{instance}',
rawurlencode($instance),
$template
);
$method = strtoupper($method) === 'POST' ? 'POST' : 'GET';
// URL in Bestandteile zerlegen
$parsed = parse_url($preparedUrl);
$path = $parsed['scheme'] . '://' . $parsed['host']
. ($parsed['path'] ?? '');
$queryPart = $parsed['query'] ?? '';
// --- Query-Placeholder extrahieren ---
preg_match_all('/\{([a-zA-Z0-9_]+)\}/', $queryPart, $queryMatches);
$queryFields = array_unique($queryMatches[1]);
// --- Path-Placeholder extrahieren ---
preg_match_all('/\{([a-zA-Z0-9_]+)\}/', $path, $pathMatches);
$pathFields = array_unique($pathMatches[1]);
// --- Action bestimmen ---
$action = $path;
// Form-Attribute bauen
$attrString = '';
foreach ($formAttributes as $key => $value) {
$attrString .= sprintf(
' %s="%s"',
htmlspecialchars($key, ENT_QUOTES),
htmlspecialchars($value, ENT_QUOTES)
);
}
$html = sprintf(
'<form method="%s" action="%s"%s>',
htmlspecialchars($method, ENT_QUOTES),
htmlspecialchars($action, ENT_QUOTES),
$attrString
);
// --- Path-Felder als hidden ---
foreach ($pathFields as $field) {
if ($field === 'instance') {
continue;
}
$value = $defaultValues[$field] ?? '';
$html .= sprintf(
'<input type="hidden" name="%s" value="%s">',
htmlspecialchars($field, ENT_QUOTES),
htmlspecialchars($value, ENT_QUOTES)
);
}
// --- Query-Felder als Textfelder ---
foreach ($queryFields as $field) {
$value = $defaultValues[$field] ?? '';
$html .='<span style="position:relative;display:inline-block;">'
.sprintf(
'<input type="text" name="%s" value="%s" placeholder="🔍" ng-model="searchInInstanceFormValue"
style="padding-right:22px;"
oninput="this.nextElementSibling.style.display=this.value?\'block\':\'none\';">',
htmlspecialchars($field, ENT_QUOTES),
htmlspecialchars($value, ENT_QUOTES)
).'<span
onclick="this.previousElementSibling.value=\'\';this.style.display=\'none\';this.previousElementSibling.focus();"
style="
display:' . ($value !== '' ? 'block' : 'none') . ';
position:absolute;
right:6px;
top:50%;
transform:translateY(-50%);
cursor:pointer;
font-weight:bold;
color:#666;
user-select:none;
"
>?</span>
</span>';
}
$html .= '<button type="submit" class="btn-sm btn-info">
<span ng-show="langIsDefault==true || langShortCode==\'en\'" ng-cloak>Search <span ng-show="searchInInstanceFormValue">for "{{searchInInstanceFormValue }}"</span> on '.ucfirst($instance).' 🔍</span>
<span ng-show="langShortCode==\'de\'" ng-cloak>Auf '.ucfirst($instance).' <span ng-show="searchInInstanceFormValue">nach "{{searchInInstanceFormValue }}"</span> suchen 🔍</span>
</button>';
$html .= '</form>';
return $html;
}
}
|