diff --git a/README.md b/README.md index 0c3362c6..1390edab 100644 --- a/README.md +++ b/README.md @@ -128,8 +128,6 @@ Before submitting design contributions, please discuss them with the Standard Eb ### Main website -- Add type hints for class variables. - - Convert ebooks from being stored in an APCu cache to our MariaDB database. (This is a big project!) - Creating a search bar for the SE Manual of Style. @@ -186,7 +184,7 @@ Before submitting design contributions, please discuss them with the Standard Eb - Check for `null` using `===` and `!==`. -- Where possible, include type hints for functions. Due to PHP limitations this may not always be possible, for example in cases where `null` may be passed or returned. +- Where possible, include type hints for class properties and all functions. - If using regex to parse HTML, use `|` as the regex delimiter instead of `/`. diff --git a/lib/ArtworkTag.php b/lib/ArtworkTag.php index 7a9f2dc5..f636230e 100644 --- a/lib/ArtworkTag.php +++ b/lib/ArtworkTag.php @@ -1,5 +1,4 @@ Name === null || strlen($this->Name) === 0){ + if(strlen($this->Name) == 0){ $error->Add(new Exceptions\InvalidArtworkTagException()); } - if($this->Url === null || strlen($this->Url) === 0){ + if($this->Url === null || strlen($this->Url) == 0){ $error->Add(new Exceptions\InvalidArtworkTagException()); } diff --git a/lib/AtomFeed.php b/lib/AtomFeed.php index 7bd56075..d8f457e8 100644 --- a/lib/AtomFeed.php +++ b/lib/AtomFeed.php @@ -1,16 +1,11 @@ Stylesheet = SITE_URL . '/feeds/atom/style'; } - // ******* // METHODS // ******* diff --git a/lib/Benefits.php b/lib/Benefits.php index 230377c3..783e0192 100644 --- a/lib/Benefits.php +++ b/lib/Benefits.php @@ -1,8 +1,8 @@ Name = $name; diff --git a/lib/Contributor.php b/lib/Contributor.php index 3cd85215..6748861b 100644 --- a/lib/Contributor.php +++ b/lib/Contributor.php @@ -1,12 +1,12 @@ Name = str_replace('\'', '’', $name); diff --git a/lib/Db.php b/lib/Db.php index c2f63aa3..ecde9a93 100644 --- a/lib/Db.php +++ b/lib/Db.php @@ -1,5 +1,4 @@ GetLastInsertedId(); diff --git a/lib/DbConnection.php b/lib/DbConnection.php index 2577edbb..f06c5f33 100644 --- a/lib/DbConnection.php +++ b/lib/DbConnection.php @@ -4,10 +4,9 @@ use function Safe\preg_match; use function Safe\posix_getpwuid; class DbConnection{ - private $_link = null; - public $IsConnected = false; - public $QueryCount = 0; - public $LastQueryAffectedRowCount = 0; + private ?\PDO $_link = null; + public int $QueryCount = 0; + public int $LastQueryAffectedRowCount = 0; public function __construct(?string $defaultDatabase = null, string $host = 'localhost', ?string $user = null, string$password = '', bool $forceUtf8 = true, bool $require = true){ if($user === null){ @@ -51,8 +50,6 @@ class DbConnection{ // We can't use persistent connections (connection pooling) because we would have race condition problems with last_insert_id() $this->_link = new \PDO($connectionString, $user, $password, $params); - - $this->IsConnected = true; } catch(Exception $ex){ if(SITE_STATUS == SITE_STATUS_DEV){ @@ -79,7 +76,7 @@ class DbConnection{ * @return Array */ public function Query(string $sql, array $params = [], string $class = 'stdClass'): array{ - if(!$this->IsConnected){ + if($this->_link === null){ return []; } @@ -245,8 +242,19 @@ class DbConnection{ // Gets the last auto-increment id public function GetLastInsertedId(): ?int{ + if($this->_link === null){ + return null; + } + $id = $this->_link->lastInsertId(); + if($id === false){ + return null; + } + else{ + $id = (int)$id; + } + if($id == 0){ return null; } diff --git a/lib/Ebook.php b/lib/Ebook.php index be61608c..ca191246 100644 --- a/lib/Ebook.php +++ b/lib/Ebook.php @@ -10,58 +10,70 @@ use function Safe\sprintf; use function Safe\shell_exec; use function Safe\substr; +/** + * @property array $GitCommits + * @property array $EbookTags + * @property array $LocTags + * @property array $Collections + * @property array $Sources + * @property array $Authors + * @property array $Illustrators + * @property array $Translators + * @property array $Contributors + * @property ?array $TocEntries + */ class Ebook{ - public $WwwFilesystemPath; - public $RepoFilesystemPath; - public $Url; - public $KindleCoverUrl; - public $EpubUrl; - public $AdvancedEpubUrl; - public $KepubUrl; - public $Azw3Url; - public $HasDownloads; + public string $WwwFilesystemPath; + public string $RepoFilesystemPath; + public string $Url; + public string $KindleCoverUrl; + public string $EpubUrl; + public string $AdvancedEpubUrl; + public string $KepubUrl; + public string $Azw3Url; + public bool $HasDownloads; public $GitCommits = []; public $Tags = []; public $LocTags = []; public $Collections = []; - public $Identifier; - public $UrlSafeIdentifier; - public $HeroImageUrl; - public $HeroImageAvifUrl; - public $HeroImage2xUrl; - public $HeroImage2xAvifUrl; - public $CoverImageUrl; - public $CoverImageAvifUrl; - public $CoverImage2xUrl; - public $CoverImage2xAvifUrl; - public $DistCoverUrl; - public $Title; - public $FullTitle; - public $AlternateTitle; - public $Description; - public $LongDescription; - public $Language; - public $WordCount; - public $ReadingEase; - public $ReadingEaseDescription; - public $ReadingTime; - public $GitHubUrl; - public $WikipediaUrl; + public string $Identifier; + public string $UrlSafeIdentifier; + public string $HeroImageUrl; + public string $HeroImageAvifUrl; + public string $HeroImage2xUrl; + public string $HeroImage2xAvifUrl; + public string $CoverImageUrl; + public string $CoverImageAvifUrl; + public string $CoverImage2xUrl; + public string $CoverImage2xAvifUrl; + public string $DistCoverUrl; + public ?string $Title = null; + public ?string $FullTitle = null; + public ?string $AlternateTitle = null; + public ?string $Description = null; + public ?string $LongDescription = null; + public ?string $Language = null; + public int $WordCount; + public float $ReadingEase; + public string $ReadingEaseDescription; + public string $ReadingTime; + public ?string $GitHubUrl = null; + public ?string $WikipediaUrl = null; public $Sources = []; - public $Authors = []; // Array of Contributors - public $AuthorsHtml; - public $AuthorsUrl; // This is a single URL even if there are multiple authors; for example, /ebooks/karl-marx_friedrich-engels/ - public $Illustrators = []; // Array of Contributors - public $Translators = []; // Array of Contributors - public $Contributors = []; // Array of Contributors - public $ContributorsHtml; - public $TitleWithCreditsHtml = ''; - public $Created; - public $Updated; - public $TextUrl; - public $TextSinglePageUrl; - public $TextSinglePageSizeNumber = null; - public $TextSinglePageSizeUnit = null; + public $Authors = []; + public string $AuthorsHtml; + public string $AuthorsUrl; // This is a single URL even if there are multiple authors; for example, /ebooks/karl-marx_friedrich-engels/ + public $Illustrators = []; + public $Translators = []; + public $Contributors = []; + public ?string $ContributorsHtml = null; + public string $TitleWithCreditsHtml = ''; + public DateTime $Created; + public DateTime $Updated; + public string $TextUrl; + public string $TextSinglePageUrl; + public ?string $TextSinglePageSizeNumber = null; + public ?string $TextSinglePageSizeUnit = null; public $TocEntries = null; // A list of non-Roman ToC entries ONLY IF the work has the 'se:is-a-collection' metadata element, null otherwise public function __construct(?string $wwwFilesystemPath = null){ @@ -384,7 +396,7 @@ class Ebook{ // Figure out the reading time. $readingTime = ceil($this->WordCount / AVERAGE_READING_WORDS_PER_MINUTE); - $this->ReadingTime = $readingTime; + $this->ReadingTime = (string)$readingTime; if($readingTime < 60){ $this->ReadingTime .= ' minute'; diff --git a/lib/EbookSource.php b/lib/EbookSource.php index 98aeb091..81ac892e 100644 --- a/lib/EbookSource.php +++ b/lib/EbookSource.php @@ -1,7 +1,7 @@ Type = $type; diff --git a/lib/EbookTag.php b/lib/EbookTag.php index 0091fc8c..d54a2760 100644 --- a/lib/EbookTag.php +++ b/lib/EbookTag.php @@ -6,7 +6,6 @@ class EbookTag extends Tag{ $this->_Url = '/subjects/' . $this->UrlName; } - // ******* // GETTERS // ******* diff --git a/lib/Email.php b/lib/Email.php index f7465bcf..01ab1fc1 100644 --- a/lib/Email.php +++ b/lib/Email.php @@ -2,20 +2,20 @@ use PHPMailer\PHPMailer\PHPMailer; use PHPMailer\PHPMailer\Exception; -use function Safe\define; -use function Safe\file_get_contents; - +/** + * @property array> $Attachments + */ class Email{ - public $To = ''; - public $ToName = ''; - public $From = ''; - public $FromName = ''; - public $ReplyTo = ''; - public $Subject = ''; - public $Body = ''; - public $TextBody = ''; + public string $To = ''; + public string $ToName = ''; + public string $From = ''; + public string $FromName = ''; + public string $ReplyTo = ''; + public string $Subject = ''; + public string $Body = ''; + public string $TextBody = ''; public $Attachments = []; - public $PostmarkStream = null; + public ?string $PostmarkStream = null; public function __construct(bool $isNoReplyEmail = false){ if($isNoReplyEmail){ @@ -35,7 +35,7 @@ class Email{ $this->ReplyTo = $this->From; } - if($this->To === null || $this->To == ''){ + if($this->To == ''){ return false; } diff --git a/lib/Feed.php b/lib/Feed.php index 50526aa3..063c7633 100644 --- a/lib/Feed.php +++ b/lib/Feed.php @@ -1,18 +1,20 @@ $Entries + */ class Feed{ - public $Url; - public $Title; + public string $Url; + public string $Title; public $Entries = []; - public $Path = null; - public $Stylesheet = null; - protected $XmlString = null; + public string $Path; + public ?string $Stylesheet = null; + protected ?string $XmlString = null; /** * @param string $title diff --git a/lib/GitCommit.php b/lib/GitCommit.php index 7cfa3750..15fea568 100644 --- a/lib/GitCommit.php +++ b/lib/GitCommit.php @@ -2,9 +2,9 @@ use Safe\DateTimeImmutable; class GitCommit{ - public $Created; - public $Message; - public $Hash; + public DateTimeImmutable $Created; + public string $Message; + public string $Hash; public function __construct(string $unixTimestamp, string $hash, string $message){ $this->Created = new DateTimeImmutable('@' . $unixTimestamp); diff --git a/lib/Image.php b/lib/Image.php index 6bb38c79..1b233879 100644 --- a/lib/Image.php +++ b/lib/Image.php @@ -7,8 +7,8 @@ use function Safe\getimagesize; use function Safe\unlink; class Image{ - public $Path; - public $MimeType; + public string $Path; + public ?ImageMimeType $MimeType; public function __construct(string $path){ $this->Path = $path; diff --git a/lib/Library.php b/lib/Library.php index 937d6c18..79c50625 100644 --- a/lib/Library.php +++ b/lib/Library.php @@ -7,14 +7,11 @@ use function Safe\filesize; use function Safe\glob; use function Safe\gmdate; use function Safe\ksort; -use function Safe\preg_match; use function Safe\preg_replace; use function Safe\shell_exec; use function Safe\sleep; -use function Safe\sort; use function Safe\usort; - class Library{ /** * @param string $query diff --git a/lib/Log.php b/lib/Log.php index 4fc68c1a..ff77e6ab 100644 --- a/lib/Log.php +++ b/lib/Log.php @@ -7,8 +7,8 @@ use function Safe\gmdate; use function Safe\substr; class Log{ - private $RequestId = null; - private $LogFilePath = null; + private string $RequestId; + private ?string $LogFilePath = null; public function __construct(?string $logFilePath){ // Get a semi-random ID to identify this request within the log. diff --git a/lib/Museum.php b/lib/Museum.php index 7cd45752..af076900 100644 --- a/lib/Museum.php +++ b/lib/Museum.php @@ -1,9 +1,8 @@ PostmarkStream = EMAIL_POSTMARK_STREAM_BROADCAST; - $em->To = $this->User->Email; - if($this->User->Name != ''){ + $em->To = $this->User->Email ?? ''; + if($this->User->Name !== null && $this->User->Name != ''){ $em->ToName = $this->User->Name; } $em->Subject = 'Action required: confirm your newsletter subscription'; diff --git a/lib/OpdsAcquisitionFeed.php b/lib/OpdsAcquisitionFeed.php index ef5f46c4..9089c3ed 100644 --- a/lib/OpdsAcquisitionFeed.php +++ b/lib/OpdsAcquisitionFeed.php @@ -2,7 +2,7 @@ use Safe\DateTime; class OpdsAcquisitionFeed extends OpdsFeed{ - public $IsCrawlable; + public bool $IsCrawlable; 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); diff --git a/lib/OpdsFeed.php b/lib/OpdsFeed.php index 581ffb07..d30ab1b7 100644 --- a/lib/OpdsFeed.php +++ b/lib/OpdsFeed.php @@ -3,7 +3,7 @@ use Safe\DateTime; use function Safe\file_put_contents; class OpdsFeed extends AtomFeed{ - public $Parent = null; // OpdsNavigationFeed class + public ?OpdsNavigationFeed $Parent = null; /** * @param string $title diff --git a/lib/OpdsNavigationEntry.php b/lib/OpdsNavigationEntry.php index a56a36ee..eb409dc3 100644 --- a/lib/OpdsNavigationEntry.php +++ b/lib/OpdsNavigationEntry.php @@ -1,13 +1,13 @@ Id = SITE_URL . $url; diff --git a/lib/OpdsNavigationFeed.php b/lib/OpdsNavigationFeed.php index f427c577..128c11fe 100644 --- a/lib/OpdsNavigationFeed.php +++ b/lib/OpdsNavigationFeed.php @@ -1,6 +1,5 @@ User !== null){ $em = new Email(); - $em->To = $this->User->Email; - $em->ToName = $this->User->Name; + $em->To = $this->User->Email ?? ''; + $em->ToName = $this->User->Name ?? ''; $em->From = EDITOR_IN_CHIEF_EMAIL_ADDRESS; $em->FromName = EDITOR_IN_CHIEF_NAME; $em->Subject = 'Thank you for supporting Standard Ebooks!'; diff --git a/lib/Payment.php b/lib/Payment.php index cf14dda0..0882c3a4 100644 --- a/lib/Payment.php +++ b/lib/Payment.php @@ -1,19 +1,18 @@ $_PollItems + * @property ?array $_PollItemsByWinner * @property string $Url * @property array $PollItems * @property array $PollItemsByWinner * @property int $VoteCount */ class Poll extends PropertiesBase{ - public $PollId; - public $Name; - public $UrlName; - public $Description; - public $Created; - public $Start; - public $End; - protected $_Url = null; + public int $PollId; + public string $Name; + public string $UrlName; + public string $Description; + public DateTime $Created; + public DateTime $Start; + public DateTime $End; + protected ?string $_Url = null; protected $_PollItems = null; protected $_PollItemsByWinner = null; - protected $_VoteCount = null; + protected ?int $_VoteCount = null; // ******* @@ -71,7 +73,7 @@ class Poll extends PropertiesBase{ $this->_PollItemsByWinner = $this->PollItems; usort($this->_PollItemsByWinner, function(PollItem $a, PollItem $b){ return $a->VoteCount <=> $b->VoteCount; }); - $this->_PollItemsByWinner = array_reverse($this->_PollItemsByWinner); + $this->_PollItemsByWinner = array_reverse($this->_PollItemsByWinner ?? []); } return $this->_PollItemsByWinner; diff --git a/lib/PollItem.php b/lib/PollItem.php index cf9ce783..6b56387a 100644 --- a/lib/PollItem.php +++ b/lib/PollItem.php @@ -1,16 +1,15 @@ UserId === null || $this->User === null){ + if($this->User === null){ $error->Add(new Exceptions\InvalidUserException()); } diff --git a/lib/PropertiesBase.php b/lib/PropertiesBase.php index 0b3c0518..1f937524 100644 --- a/lib/PropertiesBase.php +++ b/lib/PropertiesBase.php @@ -1,6 +1,4 @@ $Payments + * @property ?bool $IsRegistered * @property Benefits $Benefits + * @property ?array $_Payments */ class User extends PropertiesBase{ - public $UserId; - public $Name; - public $Email; - public $Created; - public $Uuid; - public $PasswordHash; - protected $_IsRegistered = null; + public int $UserId; + public ?string $Name; + public ?string $Email; + public DateTime $Created; + public string $Uuid; + public ?string $PasswordHash; + protected ?bool $_IsRegistered = null; protected $_Payments = null; - protected $_Benefits = null; - + protected ?Benefits $_Benefits = null; // ******* // GETTERS @@ -59,7 +60,7 @@ class User extends PropertiesBase{ return $this->_Benefits; } - protected function GetIsRegistered(): bool{ + protected function GetIsRegistered(): ?bool{ if($this->_IsRegistered === null){ // A user is "registered" if they have a benefits entry in the table. // This function will fill it out for us. diff --git a/www/newsletter/subscriptions/post.php b/www/newsletter/subscriptions/post.php index f056992c..a3f841c4 100644 --- a/www/newsletter/subscriptions/post.php +++ b/www/newsletter/subscriptions/post.php @@ -35,8 +35,8 @@ if(HttpInput::Str(POST, 'automationtest', false)){ try{ $subscription->User = new User(); $subscription->User->Email = HttpInput::Str(POST, 'email', false); - $subscription->IsSubscribedToNewsletter = HttpInput::Bool(POST, 'issubscribedtonewsletter', false); - $subscription->IsSubscribedToSummary = HttpInput::Bool(POST, 'issubscribedtosummary', false); + $subscription->IsSubscribedToNewsletter = HttpInput::Bool(POST, 'issubscribedtonewsletter') ?? false; + $subscription->IsSubscribedToSummary = HttpInput::Bool(POST, 'issubscribedtosummary') ?? false; $captcha = HttpInput::Str(SESSION, 'captcha', false) ?? ''; diff --git a/www/polls/votes/post.php b/www/polls/votes/post.php index 1be01702..9e6f3484 100644 --- a/www/polls/votes/post.php +++ b/www/polls/votes/post.php @@ -1,5 +1,4 @@