diff --git a/lib/Payment.php b/lib/Payment.php index d323c5ae..750f08e8 100644 --- a/lib/Payment.php +++ b/lib/Payment.php @@ -2,7 +2,7 @@ use Safe\DateTimeImmutable; /** - * @property User $User + * @property ?User $User */ class Payment{ use Traits\Accessor; @@ -19,6 +19,17 @@ class Payment{ protected ?User $_User = null; + /** + * @throws Exceptions\UserNotFoundException + */ + protected function GetUser(): ?User{ + if($this->_User === null && $this->UserId !== null){ + $this->_User = User::Get($this->UserId); + } + + return $this->_User; + } + // ******* // METHODS diff --git a/scripts/generate-bulk-downloads b/scripts/generate-bulk-downloads index acbdb373..535aecdd 100755 --- a/scripts/generate-bulk-downloads +++ b/scripts/generate-bulk-downloads @@ -2,7 +2,18 @@ $ebooks + */ function CreateZip(string $filePath, array $ebooks, string $type, string $webRoot): void{ $tempFilename = tempnam(sys_get_temp_dir(), "se-ebooks"); @@ -198,7 +212,7 @@ foreach($groups as $group){ mkdir($parentDir, 0775, true); } - exec('attr -q -s se-ebook-count -V ' . escapeshellarg(sizeof($collection->Ebooks)) . ' ' . escapeshellarg($parentDir)); + exec('attr -q -s se-ebook-count -V ' . escapeshellarg((string)sizeof($collection->Ebooks)) . ' ' . escapeshellarg($parentDir)); exec('attr -q -s se-label -V ' . escapeshellarg($collection->Label) . ' ' . escapeshellarg($parentDir)); exec('attr -q -s se-label-sort -V ' . escapeshellarg($collection->LabelSort) . ' ' . escapeshellarg($parentDir)); diff --git a/scripts/generate-feeds b/scripts/generate-feeds index 6272727c..079ec577 100755 --- a/scripts/generate-feeds +++ b/scripts/generate-feeds @@ -3,11 +3,13 @@ require_once('/standardebooks.org/web/lib/Core.php'); use Safe\DateTimeImmutable; + +use function Safe\exec; use function Safe\getopt; use function Safe\mkdir; use function Safe\preg_replace; -function SortByUpdatedDesc($a, $b){ +function SortByUpdatedDesc(Ebook $a, Ebook $b): int{ return $b->Updated <=> $a->Updated; } @@ -31,6 +33,10 @@ function SaveFeed(Feed $feed, bool $force, ?string $label = null, ?string $label } } +/** + * @param array> $collections + * @param array $ebooks + */ function CreateOpdsCollectionFeed(string $name, string $url, string $description, array $collections, array $ebooks, DateTimeImmutable $now, string $webRoot, OpdsNavigationFeed $opdsRoot, bool $force): void{ $collator = collator_create('en_US'); // Used for sorting letters with diacritics like in author names usort($collections, function($a, $b) use($collator){ return $collator->compare($a['sortedname'], $b['sortedname']); }); diff --git a/scripts/ingest-fa-payments b/scripts/ingest-fa-payments index 48e4b1a2..58827005 100755 --- a/scripts/ingest-fa-payments +++ b/scripts/ingest-fa-payments @@ -18,6 +18,7 @@ use Facebook\WebDriver\Firefox\FirefoxOptions; use Safe\DateTimeImmutable; use function Safe\file_get_contents; +use function Safe\file_put_contents; use function Safe\preg_replace; use function Safe\putenv; use function Safe\set_time_limit; @@ -51,7 +52,7 @@ $faItemsPerPage = 20; // How many items are on a full page of FA results? // General plan: Read /tmp/last-fa-donation to see what the last transaction ID was that we processed. // If /tmp/last-fa-donation doesn't exist, get all transactions from today and create the file. -function InsertTransaction($transactionId){ +function InsertTransaction(string $transactionId): bool{ $exists = Db::QueryInt('SELECT exists( select * from @@ -151,7 +152,7 @@ try{ $transactionId = trim($td->getDomProperty('textContent')); - if($transactionId === null){ + if($transactionId === ''){ continue; } @@ -173,7 +174,7 @@ try{ $transactionId = trim($td->getDomProperty('textContent')); - if($transactionId === null){ + if($transactionId === ''){ continue; } @@ -215,6 +216,6 @@ catch(Exception $ex){ throw $ex; } finally{ - $driver->quit(); + $driver?->quit(); } ?> diff --git a/scripts/process-pending-payments b/scripts/process-pending-payments index 05cc87a8..64646dd8 100755 --- a/scripts/process-pending-payments +++ b/scripts/process-pending-payments @@ -160,14 +160,14 @@ try{ $payment->Amount = floatval(str_replace('$', '', trim($detailsRow->findElement(WebDriverBy::xpath('//td[preceding-sibling::th[normalize-space(.) = "Total Amount"]]'))->getText()))); $payment->Fee = floatval(str_replace('$', '', trim($detailsRow->findElement(WebDriverBy::xpath('//td[preceding-sibling::th[normalize-space(.) = "Fee"]]'))->getText()))); - $transactionId = $detailsRow->findElement(WebDriverBy::xpath('//td[preceding-sibling::th[normalize-space(.) = "ID"]]'))->getText(); + $transactionId = (string)($detailsRow->findElement(WebDriverBy::xpath('//td[preceding-sibling::th[normalize-space(.) = "ID"]]'))->getText()); $transactionId = str_replace('View on FS', '', $transactionId); $transactionId = str_replace('View on Finance', '', $transactionId); $payment->TransactionId = trim($transactionId); // We might also get a case where the donation is on behalf of a company match, but there's not really a way to distinguish that. Do a rough check. // See donation 00b60a22-eafa-44cb-9850-54bef9763e8d - if($payment->User !== null && preg_match('/\b(L\.?L\.?C\.?|Foundation|President|Fund|Charitable)\b/ius', $payment->User->Name)){ + if($payment->User !== null && preg_match('/\b(L\.?L\.?C\.?|Foundation|President|Fund|Charitable)\b/ius', $payment->User->Name ?? '')){ $payment->User = null; } @@ -234,8 +234,8 @@ try{ $log->Write('Sending thank you email to patron donor donating extra.'); $em = new Email(); - $em->To = $payment->User->Email; - $em->ToName = $payment->User->Name; + $em->To = $payment->User->Email ?? ''; + $em->ToName = $payment->User->Name ?? ''; $em->From = EDITOR_IN_CHIEF_EMAIL_ADDRESS; $em->FromName = EDITOR_IN_CHIEF_NAME; $em->Subject = 'Thank you for supporting Standard Ebooks!'; @@ -272,8 +272,8 @@ try{ if(!$payment->IsRecurring || $previousPaymentCount == 1){ $log->Write('Sending thank you email to non-patron donor.'); $em = new Email(); - $em->To = $payment->User->Email; - $em->ToName = $payment->User->Name; + $em->To = $payment->User->Email ?? ''; + $em->ToName = $payment->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/scripts/update-patrons-circle b/scripts/update-patrons-circle index 4010e0a7..f09e525f 100755 --- a/scripts/update-patrons-circle +++ b/scripts/update-patrons-circle @@ -4,6 +4,10 @@ require_once('/standardebooks.org/web/lib/Core.php'); use Safe\DateTimeImmutable; +use function Safe\file_get_contents; +use function Safe\preg_match_all; +use function Safe\shell_exec; + // Get a list of payments that are within 1 year / 45 days of today, and deactivate Patrons Circle members // who aren't in that list. // We give a 15 day grace period to Patrons Circle members because sometimes FA can be delayed in charging. @@ -33,7 +37,7 @@ if(sizeof($expiredPatrons) > 0){ // We can't use the Library class to get ebooks because this script is typically run via cron or CLI, // which doesn't have access PHP-FMP's APCu cache. - foreach(explode("\n", trim(shell_exec('find ' . EBOOKS_DIST_PATH . ' -name "content.opf"') ?? '')) as $filename){ + foreach(explode("\n", trim(shell_exec('find ' . EBOOKS_DIST_PATH . ' -name "content.opf"'))) as $filename){ $metadata = file_get_contents($filename); // Don't create a new Ebook object because that's very slow. Just do a regex match for speed. @@ -77,7 +81,7 @@ if(sizeof($expiredPatrons) > 0){ $em->From = EDITOR_IN_CHIEF_EMAIL_ADDRESS; $em->FromName = EDITOR_IN_CHIEF_NAME; $em->To = $patron->User->Email; - $em->ToName = $patron->User->Name; + $em->ToName = $patron->User->Name ?? ''; $em->Subject = 'Will you still help us make free, beautiful digital literature?'; if($lastPayment[0]->IsRecurring){