mirror of
https://github.com/standardebooks/web.git
synced 2025-07-21 14:55:13 -04:00
Completely type hint template functions and switch to named arguments
This commit is contained in:
parent
6108b5e53d
commit
124e8343fc
125 changed files with 542 additions and 450 deletions
|
@ -26,7 +26,9 @@ class AtomFeed extends Feed{
|
|||
|
||||
protected function GetXmlString(): string{
|
||||
if(!isset($this->_XmlString)){
|
||||
$feed = Template::AtomFeed(['id' => $this->Id, 'url' => $this->Url, 'title' => $this->Title, 'subtitle' => $this->Subtitle, 'updated' => $this->Updated, 'entries' => $this->Entries]);
|
||||
/** @var array<Ebook> $entries */
|
||||
$entries = $this->Entries;
|
||||
$feed = Template::AtomFeed(id: $this->Id, url: $this->Url, title: $this->Title, subtitle: $this->Subtitle, updated: $this->Updated, entries: $entries);
|
||||
|
||||
$this->_XmlString = $this->CleanXmlString($feed);
|
||||
}
|
||||
|
|
|
@ -98,8 +98,8 @@ class NewsletterSubscription{
|
|||
$em->ToName = $this->User->Name;
|
||||
}
|
||||
$em->Subject = 'Action required: confirm your newsletter subscription';
|
||||
$em->Body = Template::EmailNewsletterConfirmation(['subscription' => $this, 'isSubscribedToSummary' => $this->IsSubscribedToSummary, 'isSubscribedToNewsletter' => $this->IsSubscribedToNewsletter]);
|
||||
$em->TextBody = Template::EmailNewsletterConfirmationText(['subscription' => $this, 'isSubscribedToSummary' => $this->IsSubscribedToSummary, 'isSubscribedToNewsletter' => $this->IsSubscribedToNewsletter]);
|
||||
$em->Body = Template::EmailNewsletterConfirmation(subscription: $this, isSubscribedToSummary: $this->IsSubscribedToSummary, isSubscribedToNewsletter: $this->IsSubscribedToNewsletter);
|
||||
$em->TextBody = Template::EmailNewsletterConfirmationText(subscription: $this, isSubscribedToSummary: $this->IsSubscribedToSummary, isSubscribedToNewsletter: $this->IsSubscribedToNewsletter);
|
||||
$em->Send();
|
||||
}
|
||||
|
||||
|
|
|
@ -1,7 +1,13 @@
|
|||
<?
|
||||
/**
|
||||
* @property array<Ebook> $Entries
|
||||
*/
|
||||
class OpdsAcquisitionFeed extends OpdsFeed{
|
||||
public bool $IsCrawlable;
|
||||
|
||||
/**
|
||||
* @param array<Ebook> $entries
|
||||
*/
|
||||
public function __construct(string $title, string $subtitle, string $url, string $path, array $entries, ?OpdsNavigationFeed $parent, bool $isCrawlable = false){
|
||||
parent::__construct($title, $subtitle, $url, $path, $entries, $parent);
|
||||
$this->IsCrawlable = $isCrawlable;
|
||||
|
@ -13,6 +19,6 @@ class OpdsAcquisitionFeed extends OpdsFeed{
|
|||
// *******
|
||||
|
||||
protected function GetXmlString(): string{
|
||||
return $this->_XmlString ??= $this->CleanXmlString(Template::OpdsAcquisitionFeed(['id' => $this->Id, 'url' => $this->Url, 'title' => $this->Title, 'parentUrl' => $this->Parent ? $this->Parent->Url : null, 'updated' => $this->Updated, 'isCrawlable' => $this->IsCrawlable, 'subtitle' => $this->Subtitle, 'entries' => $this->Entries]));
|
||||
return $this->_XmlString ??= $this->CleanXmlString(Template::OpdsAcquisitionFeed(id: $this->Id, url: $this->Url, title: $this->Title, parentUrl: $this->Parent->Url ?? '', updated: $this->Updated, isCrawlable: $this->IsCrawlable, subtitle: $this->Subtitle, entries: $this->Entries));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,6 +2,9 @@
|
|||
use Safe\DateTimeImmutable;
|
||||
use function Safe\file_put_contents;
|
||||
|
||||
/**
|
||||
* @property array<Ebook|OpdsNavigationEntry> $Entries
|
||||
*/
|
||||
abstract class OpdsFeed extends AtomFeed{
|
||||
public ?OpdsNavigationFeed $Parent = null;
|
||||
|
||||
|
|
|
@ -2,6 +2,9 @@
|
|||
use Safe\DateTimeImmutable;
|
||||
use function Safe\file_get_contents;
|
||||
|
||||
/**
|
||||
* @property array<OpdsNavigationEntry> $Entries
|
||||
*/
|
||||
class OpdsNavigationFeed extends OpdsFeed{
|
||||
/**
|
||||
* @param array<OpdsNavigationEntry> $entries
|
||||
|
@ -38,6 +41,6 @@ class OpdsNavigationFeed extends OpdsFeed{
|
|||
// *******
|
||||
|
||||
protected function GetXmlString(): string{
|
||||
return $this->_XmlString ??= $this->CleanXmlString(Template::OpdsNavigationFeed(['id' => $this->Id, 'url' => $this->Url, 'title' => $this->Title, 'parentUrl' => $this->Parent ? $this->Parent->Url : null, 'updated' => $this->Updated, 'subtitle' => $this->Subtitle, 'entries' => $this->Entries]));
|
||||
return $this->_XmlString ??= $this->CleanXmlString(Template::OpdsNavigationFeed(id: $this->Id, url: $this->Url, title: $this->Title, parentUrl: $this->Parent->Url ?? '', updated: $this->Updated, subtitle: $this->Subtitle, entries: $this->Entries));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -83,8 +83,8 @@ class Patron{
|
|||
$em->From = EDITOR_IN_CHIEF_EMAIL_ADDRESS;
|
||||
$em->FromName = EDITOR_IN_CHIEF_NAME;
|
||||
$em->Subject = 'Thank you for supporting Standard Ebooks!';
|
||||
$em->Body = Template::EmailPatronsCircleWelcome(['isAnonymous' => $this->IsAnonymous, 'isReturning' => $isReturning]);
|
||||
$em->TextBody = Template::EmailPatronsCircleWelcomeText(['isAnonymous' => $this->IsAnonymous, 'isReturning' => $isReturning]);
|
||||
$em->Body = Template::EmailPatronsCircleWelcome(isAnonymous: $this->IsAnonymous, isReturning: $isReturning);
|
||||
$em->TextBody = Template::EmailPatronsCircleWelcomeText(isAnonymous: $this->IsAnonymous, isReturning: $isReturning);
|
||||
$em->Send();
|
||||
|
||||
if(!$isReturning){
|
||||
|
@ -92,8 +92,8 @@ class Patron{
|
|||
$em->To = ADMIN_EMAIL_ADDRESS;
|
||||
$em->From = ADMIN_EMAIL_ADDRESS;
|
||||
$em->Subject = 'New Patrons Circle member';
|
||||
$em->Body = Template::EmailAdminNewPatron(['patron' => $this, 'payment' => $this->User->Payments[0]]);
|
||||
$em->TextBody = Template::EmailAdminNewPatronText(['patron' => $this, 'payment' => $this->User->Payments[0]]);;
|
||||
$em->Body = Template::EmailAdminNewPatron(patron: $this, payment: $this->User->Payments[0]);
|
||||
$em->TextBody = Template::EmailAdminNewPatronText(patron: $this, payment: $this->User->Payments[0]);;
|
||||
$em->Send();
|
||||
}
|
||||
}
|
||||
|
@ -134,8 +134,8 @@ class Patron{
|
|||
}
|
||||
else{
|
||||
// Email one time donors who have expired after one year.
|
||||
$em->Body = Template::EmailPatronsCircleCompleted(['ebooksThisYear' => $ebooksThisYear]);
|
||||
$em->TextBody = Template::EmailPatronsCircleCompletedText(['ebooksThisYear' => $ebooksThisYear]);
|
||||
$em->Body = Template::EmailPatronsCircleCompleted(ebooksThisYear: $ebooksThisYear);
|
||||
$em->TextBody = Template::EmailPatronsCircleCompletedText(ebooksThisYear: $ebooksThisYear);
|
||||
}
|
||||
|
||||
$em->Send();
|
||||
|
|
|
@ -397,8 +397,8 @@ final class Project{
|
|||
$em->From = ADMIN_EMAIL_ADDRESS;
|
||||
$em->To = $this->Manager->Email;
|
||||
$em->Subject = 'New ebook project to manage and review';
|
||||
$em->Body = Template::EmailManagerNewProject(['project' => $this, 'role' => 'manage and review', 'user' => $this->Manager]);
|
||||
$em->TextBody = Template::EmailManagerNewProjectText(['project' => $this, 'role' => 'manage and review', 'user' => $this->Manager]);
|
||||
$em->Body = Template::EmailManagerNewProject(project: $this, role: 'manage and review', user: $this->Manager);
|
||||
$em->TextBody = Template::EmailManagerNewProjectText(project: $this, role: 'manage and review', user: $this->Manager);
|
||||
$em->Send();
|
||||
}
|
||||
}
|
||||
|
@ -409,8 +409,8 @@ final class Project{
|
|||
$em->From = ADMIN_EMAIL_ADDRESS;
|
||||
$em->To = $this->Manager->Email;
|
||||
$em->Subject = 'New ebook project to manage';
|
||||
$em->Body = Template::EmailManagerNewProject(['project' => $this, 'role' => 'manage', 'user' => $this->Manager]);
|
||||
$em->TextBody = Template::EmailManagerNewProjectText(['project' => $this, 'role' => 'manage', 'user' => $this->Manager]);
|
||||
$em->Body = Template::EmailManagerNewProject(project: $this, role: 'manage', user: $this->Manager);
|
||||
$em->TextBody = Template::EmailManagerNewProjectText(project: $this, role: 'manage', user: $this->Manager);
|
||||
$em->Send();
|
||||
}
|
||||
|
||||
|
@ -420,8 +420,8 @@ final class Project{
|
|||
$em->From = ADMIN_EMAIL_ADDRESS;
|
||||
$em->To = $this->Reviewer->Email;
|
||||
$em->Subject = 'New ebook project to review';
|
||||
$em->Body = Template::EmailManagerNewProject(['project' => $this, 'role' => 'review', 'user' => $this->Reviewer]);
|
||||
$em->TextBody = Template::EmailManagerNewProjectText(['project' => $this, 'role' => 'review', 'user' => $this->Reviewer]);
|
||||
$em->Body = Template::EmailManagerNewProject(project: $this, role: 'review', user: $this->Reviewer);
|
||||
$em->TextBody = Template::EmailManagerNewProjectText(project: $this, role: 'review', user: $this->Reviewer);
|
||||
$em->Send();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,6 +3,9 @@ use function Safe\file_get_contents;
|
|||
use function Safe\filesize;
|
||||
use function Safe\preg_replace;
|
||||
|
||||
/**
|
||||
* @property array<Ebook> $Entries
|
||||
*/
|
||||
class RssFeed extends Feed{
|
||||
public string $Description;
|
||||
|
||||
|
@ -21,7 +24,7 @@ class RssFeed extends Feed{
|
|||
// *******
|
||||
|
||||
protected function GetXmlString(): string{
|
||||
return $this->_XmlString ??= $this->CleanXmlString(Template::RssFeed(['url' => $this->Url, 'description' => $this->Description, 'title' => $this->Title, 'entries' => $this->Entries, 'updated' => NOW]));
|
||||
return $this->_XmlString ??= $this->CleanXmlString(Template::RssFeed(url: $this->Url, description: $this->Description, title: $this->Title, entries: $this->Entries, updated: NOW));
|
||||
}
|
||||
|
||||
public function SaveIfChanged(): bool{
|
||||
|
|
117
lib/Template.php
117
lib/Template.php
|
@ -1,62 +1,65 @@
|
|||
<?
|
||||
use function Safe\ob_end_clean;
|
||||
use function Safe\ob_start;
|
||||
|
||||
class Template{
|
||||
/**
|
||||
* @param array<mixed> $arguments
|
||||
*/
|
||||
protected static function Get(string $templateName, array $arguments = []): string{
|
||||
// Expand the passed variables to make them available to the included template.
|
||||
// We use these funny names so that we can use 'name' and 'value' as template variables if we want to.
|
||||
foreach($arguments as $innerName => $innerValue){
|
||||
$$innerName = $innerValue;
|
||||
}
|
||||
|
||||
ob_start();
|
||||
include(TEMPLATES_PATH . '/' . $templateName . '.php');
|
||||
$contents = ob_get_contents() ?: '';
|
||||
ob_end_clean();
|
||||
|
||||
return $contents;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<mixed> $arguments
|
||||
*/
|
||||
public static function __callStatic(string $function, array $arguments): string{
|
||||
if(isset($arguments[0]) && is_array($arguments[0])){
|
||||
return self::Get($function, $arguments[0]);
|
||||
}
|
||||
else{
|
||||
return self::Get($function, $arguments);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Exit the script while outputting the given HTTP code.
|
||||
*
|
||||
* @param bool $showPage If **`TRUE`**, show a special page given the HTTP code (like a 404 page).
|
||||
*
|
||||
* @return never
|
||||
*/
|
||||
public static function ExitWithCode(Enums\HttpCode $httpCode, bool $showPage = true, Enums\HttpRequestType $requestType = Enums\HttpRequestType::Web): void{
|
||||
http_response_code($httpCode->value);
|
||||
|
||||
if($requestType == Enums\HttpRequestType::Web && $showPage){
|
||||
switch($httpCode){
|
||||
case Enums\HttpCode::Forbidden:
|
||||
include(WEB_ROOT . '/403.php');
|
||||
break;
|
||||
case Enums\HttpCode::NotFound:
|
||||
include(WEB_ROOT . '/404.php');
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
exit();
|
||||
}
|
||||
use Safe\DateTimeImmutable;
|
||||
|
||||
/**
|
||||
* @method static string ArtworkForm(Artwork $artwork, $isEditForm = false)
|
||||
* @method static string ArtworkList(array<Artwork> $artworks)
|
||||
* @method static string AtomFeed(string $id, string $url, string $title, ?string $subtitle = null, DateTimeImmutable $updated, array<Ebook> $entries)
|
||||
* @method static string AtomFeedEntry(Ebook $entry)
|
||||
* @method static string BulkDownloadTable(string $label, array<stdClass> $collections)
|
||||
* @method static string CollectionDescriptor(?CollectionMembership $collectionMembership)
|
||||
* @method static string ContributeAlert()
|
||||
* @method static string DonationAlert()
|
||||
* @method static string DonationCounter(bool $autoHide = true, bool $showDonateButton = true)
|
||||
* @method static string DonationProgress(bool $autoHide = true, bool $showDonateButton = true)
|
||||
* @method static string EbookCarousel(array<Ebook> $carousel, bool $isMultiSize = false)
|
||||
* @method static string EbookGrid(array<Ebook> $ebooks, ?Collection $collection = null, Enums\ViewType $view = Enums\ViewType::Grid)
|
||||
* @method static string EbookMetadata(Ebook $ebook, bool $showPlaceholderMetadata = false)
|
||||
* @method static string EbookPlaceholderForm(Ebook $ebook, bool $isEditForm = false, bool $showProjectForm = true)
|
||||
* @method static string EmailAdminNewPatron(Patron $patron, Payment $payment)
|
||||
* @method static string EmailAdminNewPatronText(Patron $patron, Payment $payment)
|
||||
* @method static string EmailAdminUnprocessedDonations()
|
||||
* @method static string EmailAdminUnprocessedDonationsText()
|
||||
* @method static string EmailDonationProcessingFailed(string $exception)
|
||||
* @method static string EmailDonationProcessingFailedText(string $exception)
|
||||
* @method static string EmailDonationThankYou()
|
||||
* @method static string EmailDonationThankYouText()
|
||||
* @method static string EmailFooter(bool $includeLinks = true)
|
||||
* @method static string EmailFooterText()
|
||||
* @method static string EmailHeader(?string $preheader = null, bool $hasLetterhead = false, bool $hasAdminTable = false)
|
||||
* @method static string EmailManagerNewProject(Project $project, string $role, User $user)
|
||||
* @method static string EmailManagerNewProjectText(Project $project, string $role, User $user)
|
||||
* @method static string EmailNewsletterConfirmation(bool $isSubscribedToNewsletter, bool $isSubscribedToSummary, NewsletterSubscription $subscription)
|
||||
* @method static string EmailNewsletterConfirmationText(bool $isSubscribedToNewsletter, bool $isSubscribedToSummary, NewsletterSubscription $subscription)
|
||||
* @method static string EmailPatronsCircleCompleted(int $ebooksThisYear)
|
||||
* @method static string EmailPatronsCircleCompletedText(int $ebooksThisYear)
|
||||
* @method static string EmailPatronsCircleRecurringCompleted()
|
||||
* @method static string EmailPatronsCircleRecurringCompletedText()
|
||||
* @method static string EmailPatronsCircleWelcome(bool $isAnonymous, bool $isReturning)
|
||||
* @method static string EmailPatronsCircleWelcomeText(bool $isAnonymous, bool $isReturning)
|
||||
* @method static string EmailProjectAbandoned()
|
||||
* @method static string EmailProjectAbandonedText()
|
||||
* @method static string EmailProjectStalled()
|
||||
* @method static string EmailProjectStalledText()
|
||||
* @method static string Error(?Exception $exception)
|
||||
* @method static string FeedHowTo()
|
||||
* @method static string Footer()
|
||||
* @method static string Header(?string $title = null, ?string $highlight = null, ?string $description = null, bool $isManual = false, bool $isXslt = false, ?string $feedUrl = null, ?string $feedTitle = null, bool $isErrorPage = false, ?string $downloadUrl = null, ?string $canonicalUrl = null, ?string $coverUrl = null, string $ogType = 'website', array<string> $css = [])
|
||||
* @method static string ImageCopyrightNotice()
|
||||
* @method static string OpdsAcquisitionEntry(Ebook $entry)
|
||||
* @method static string OpdsAcquisitionFeed(string $id, string $url, string $parentUrl, string $title, ?string $subtitle, DateTimeImmutable $updated, array<Ebook> $entries, bool $isCrawlable = false)
|
||||
* @method static string OpdsNavigationFeed(string $id, string $url, ?string $parentUrl, string $title, ?string $subtitle, DateTimeImmutable $updated, array<OpdsNavigationEntry> $entries)
|
||||
* @method static string ProjectDetailsTable(Project $project, bool $useFullyQualifiedUrls = false, bool $showTitle = true, bool $showArtworkStatus = true)
|
||||
* @method static string ProjectForm(Project $project, $areFieldsRequired = true, $isEditForm = false)
|
||||
* @method static string ProjectsTable(array<Project> $projects, bool $includeTitle = true, bool $includeStatus = true, bool $showEditButton = false)
|
||||
* @method static string RealisticEbook(Ebook $ebook)
|
||||
* @method static string RssEntry(Ebook $entry)
|
||||
* @method static string RssFeed(string $title, string $description, DateTimeImmutable $updated, string $url, array<Ebook> $entries)
|
||||
* @method static string SearchForm(string $query, array<string> $tags, Enums\EbookSortType $sort, Enums\ViewType $view, int $perPage)
|
||||
* @method static string UserForm(User $user, Enums\PasswordActionType $passwordAction, bool $generateNewUuid, bool $isEditForm = false)
|
||||
* @method static string WantedEbooksList(array<Ebook> $ebooks, bool $showPlaceholderMetadata)
|
||||
*/
|
||||
class Template extends TemplateBase{
|
||||
/**
|
||||
* Redirect the user to the login page.
|
||||
*
|
||||
|
|
80
lib/TemplateBase.php
Normal file
80
lib/TemplateBase.php
Normal file
|
@ -0,0 +1,80 @@
|
|||
<?
|
||||
use function Safe\ob_end_clean;
|
||||
use function Safe\ob_start;
|
||||
|
||||
/**
|
||||
* A simple templating class that reads directly from PHP files.
|
||||
*
|
||||
* The `Template` class must extend the `TemplateBase` class. Methods corresponding to each template file are annotated using PHPDoc on the `Template` class.
|
||||
*
|
||||
* Place template files in `TEMPLATES_PATH`. Calling `Template::MyTemplateFilename(variable: value ...)` will expand passed in variables, execute `TEMPLATES_PATH/MyTemplateFilename.php`, and output the string contents of the executed PHP. For example:
|
||||
*
|
||||
* ````php
|
||||
* <?
|
||||
* // Outputs the contents of ``TEMPLATES_PATH`/Header.php`. Inside that file, the variable `$title` will be available.
|
||||
* print(Template::Header(title: 'My Title'));
|
||||
* ````
|
||||
*
|
||||
* # Template conventions
|
||||
*
|
||||
* At the top of each template file, use PHPDoc to define required variables and nullable optional variables that are `null` by default. Next, optional variables with default values are defined with the `$varName ??= $defaultValue;` pattern. For example:
|
||||
*
|
||||
* ````php
|
||||
* <?
|
||||
* // TEMPLATES_PATH/Header.php
|
||||
*
|
||||
* // @var string $title Required.
|
||||
* // @var ?string $url Optional but nullable, we define the type of `string` here.
|
||||
*
|
||||
* $url ??= null; // Optional and nullable. The type was defined in the above PHPDoc, and we set the default as `null` here.
|
||||
* $isFeed ??= false; // Optional and not nullable. Both the type and the default value are set here.
|
||||
* ?>
|
||||
* <?= $title ?>
|
||||
* <? if($isFeed){ ?>
|
||||
* <?= $url ?>
|
||||
* <? } ?>
|
||||
* ````
|
||||
*/
|
||||
abstract class TemplateBase{
|
||||
/**
|
||||
* @param array<string, mixed> $arguments
|
||||
*/
|
||||
public static function __callStatic(string $function, array $arguments): string{
|
||||
// Expand the passed variables to make them available to the included template.
|
||||
// We use these funny names so that we can use `name` and `value` as template variables if we want to.
|
||||
foreach($arguments as $innerName => $innerValue){
|
||||
$$innerName = $innerValue;
|
||||
}
|
||||
|
||||
ob_start();
|
||||
include(TEMPLATES_PATH . '/' . $function . '.php');
|
||||
$contents = ob_get_contents() ?: '';
|
||||
ob_end_clean();
|
||||
|
||||
return $contents;
|
||||
}
|
||||
|
||||
/**
|
||||
* Exit the script while outputting the given HTTP code.
|
||||
*
|
||||
* @param bool $showPage If **`TRUE`**, show a special page given the HTTP code (like a 404 page).
|
||||
*
|
||||
* @return never
|
||||
*/
|
||||
public static function ExitWithCode(Enums\HttpCode $httpCode, bool $showPage = true, Enums\HttpRequestType $requestType = Enums\HttpRequestType::Web): void{
|
||||
http_response_code($httpCode->value);
|
||||
|
||||
if($requestType == Enums\HttpRequestType::Web && $showPage){
|
||||
switch($httpCode){
|
||||
case Enums\HttpCode::Forbidden:
|
||||
include(WEB_ROOT . '/403.php');
|
||||
break;
|
||||
case Enums\HttpCode::NotFound:
|
||||
include(WEB_ROOT . '/404.php');
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
exit();
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue