Done a round of phpstan fixes

This commit is contained in:
Dan Brown 2021-11-06 00:32:01 +00:00
parent 5c6a6b50a0
commit 8d7c8ac8bf
No known key found for this signature in database
GPG Key ID: 46D9F943C24A2EF9
24 changed files with 72 additions and 84 deletions

View File

@ -90,8 +90,9 @@ class CommentRepo
*/ */
protected function getNextLocalId(Entity $entity): int protected function getNextLocalId(Entity $entity): int
{ {
$comments = $entity->comments(false)->orderBy('local_id', 'desc')->first(); /** @var Comment $comment */
$comment = $entity->comments(false)->orderBy('local_id', 'desc')->first();
return ($comments->local_id ?? 0) + 1; return ($comment->local_id ?? 0) + 1;
} }
} }

View File

@ -94,7 +94,7 @@ class LdapSessionGuard extends ExternalBaseSessionGuard
} }
// Attach avatar if non-existent // Attach avatar if non-existent
if (is_null($user->avatar)) { if (!$user->avatar()->exists()) {
$this->ldapService->saveAndAttachAvatar($user, $userDetails); $this->ldapService->saveAndAttachAvatar($user, $userDetails);
} }

View File

@ -10,14 +10,10 @@ namespace BookStack\Auth\Access;
class Ldap class Ldap
{ {
/** /**
* Connect to a LDAP server. * Connect to an LDAP server.
*
* @param string $hostName
* @param int $port
*
* @return resource * @return resource
*/ */
public function connect($hostName, $port) public function connect(string $hostName, int $port)
{ {
return ldap_connect($hostName, $port); return ldap_connect($hostName, $port);
} }
@ -26,12 +22,9 @@ class Ldap
* Set the value of a LDAP option for the given connection. * Set the value of a LDAP option for the given connection.
* *
* @param resource $ldapConnection * @param resource $ldapConnection
* @param int $option
* @param mixed $value * @param mixed $value
*
* @return bool
*/ */
public function setOption($ldapConnection, $option, $value) public function setOption($ldapConnection, int $option, $value): bool
{ {
return ldap_set_option($ldapConnection, $option, $value); return ldap_set_option($ldapConnection, $option, $value);
} }
@ -47,12 +40,9 @@ class Ldap
/** /**
* Set the version number for the given ldap connection. * Set the version number for the given ldap connection.
* *
* @param $ldapConnection * @param resource $ldapConnection
* @param $version
*
* @return bool
*/ */
public function setVersion($ldapConnection, $version) public function setVersion($ldapConnection, int $version): bool
{ {
return $this->setOption($ldapConnection, LDAP_OPT_PROTOCOL_VERSION, $version); return $this->setOption($ldapConnection, LDAP_OPT_PROTOCOL_VERSION, $version);
} }

View File

@ -49,9 +49,10 @@ class ResetMfa extends Command
return 1; return 1;
} }
/** @var User $user */
$field = $id ? 'id' : 'email'; $field = $id ? 'id' : 'email';
$value = $id ?: $email; $value = $id ?: $email;
/** @var User $user */
$user = User::query() $user = User::query()
->where($field, '=', $value) ->where($field, '=', $value)
->first(); ->first();

View File

@ -3,13 +3,14 @@
namespace BookStack\Entities\Models; namespace BookStack\Entities\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Support\Collection; use Illuminate\Support\Collection;
/** /**
* Class Chapter. * Class Chapter.
* *
* @property Collection<Page> $pages * @property Collection<Page> $pages
* @property mixed description * @property string $description
*/ */
class Chapter extends BookChild class Chapter extends BookChild
{ {
@ -22,12 +23,8 @@ class Chapter extends BookChild
/** /**
* Get the pages that this chapter contains. * Get the pages that this chapter contains.
*
* @param string $dir
*
* @return mixed
*/ */
public function pages($dir = 'ASC') public function pages(string $dir = 'ASC'): HasMany
{ {
return $this->hasMany(Page::class)->orderBy('priority', $dir); return $this->hasMany(Page::class)->orderBy('priority', $dir);
} }
@ -35,7 +32,7 @@ class Chapter extends BookChild
/** /**
* Get the url of this chapter. * Get the url of this chapter.
*/ */
public function getUrl($path = ''): string public function getUrl(string $path = ''): string
{ {
$parts = [ $parts = [
'books', 'books',

View File

@ -9,7 +9,7 @@ use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\MorphTo; use Illuminate\Database\Eloquent\Relations\MorphTo;
/** /**
* @property Model deletable * @property Model $deletable
*/ */
class Deletion extends Model implements Loggable class Deletion extends Model implements Loggable
{ {
@ -22,7 +22,7 @@ class Deletion extends Model implements Loggable
} }
/** /**
* The the user that performed the deletion. * Get the user that performed the deletion.
*/ */
public function deleter(): BelongsTo public function deleter(): BelongsTo
{ {
@ -48,9 +48,13 @@ class Deletion extends Model implements Loggable
{ {
$deletable = $this->deletable()->first(); $deletable = $this->deletable()->first();
if ($deletable instanceof Entity) {
return "Deletion ({$this->id}) for {$deletable->getType()} ({$deletable->id}) {$deletable->name}"; return "Deletion ({$this->id}) for {$deletable->getType()} ({$deletable->id}) {$deletable->name}";
} }
return "Deletion ({$this->id})";
}
/** /**
* Get a URL for this specific deletion. * Get a URL for this specific deletion.
*/ */

View File

@ -106,7 +106,7 @@ class Page extends BookChild
/** /**
* Get the url of this page. * Get the url of this page.
*/ */
public function getUrl($path = ''): string public function getUrl(string $path = ''): string
{ {
$parts = [ $parts = [
'books', 'books',

View File

@ -22,6 +22,8 @@ use Illuminate\Database\Eloquent\Relations\BelongsTo;
* @property string $html * @property string $html
* @property int $revision_number * @property int $revision_number
* @property Page $page * @property Page $page
*
* @property-read ?User $createdBy
*/ */
class PageRevision extends Model class PageRevision extends Model
{ {

View File

@ -35,7 +35,13 @@ class PageEditActivity
$pageDraftEdits = $this->activePageEditingQuery(60)->get(); $pageDraftEdits = $this->activePageEditingQuery(60)->get();
$count = $pageDraftEdits->count(); $count = $pageDraftEdits->count();
$userMessage = $count > 1 ? trans('entities.pages_draft_edit_active.start_a', ['count' => $count]) : trans('entities.pages_draft_edit_active.start_b', ['userName' => $pageDraftEdits->first()->createdBy->name]); $userMessage = trans('entities.pages_draft_edit_active.start_a', ['count' => $count]);
if ($count === 1) {
/** @var PageRevision $firstDraft */
$firstDraft = $pageDraftEdits->first();
$userMessage = trans('entities.pages_draft_edit_active.start_b', ['userName' => $firstDraft->createdBy->name ?? '']);
}
$timeMessage = trans('entities.pages_draft_edit_active.time_b', ['minCount'=> 60]); $timeMessage = trans('entities.pages_draft_edit_active.time_b', ['minCount'=> 60]);
return trans('entities.pages_draft_edit_active.message', ['start' => $userMessage, 'time' => $timeMessage]); return trans('entities.pages_draft_edit_active.message', ['start' => $userMessage, 'time' => $timeMessage]);

View File

@ -47,7 +47,7 @@ class SearchRunner
/** /**
* Search all entities in the system. * Search all entities in the system.
* The provided count is for each entity to search, * The provided count is for each entity to search,
* Total returned could can be larger and not guaranteed. * Total returned could be larger and not guaranteed.
*/ */
public function searchEntities(SearchOptions $searchOpts, string $entityType = 'all', int $page = 1, int $count = 20, string $action = 'view'): array public function searchEntities(SearchOptions $searchOpts, string $entityType = 'all', int $page = 1, int $count = 20, string $action = 'view'): array
{ {
@ -68,11 +68,15 @@ class SearchRunner
if (!in_array($entityType, $entityTypes)) { if (!in_array($entityType, $entityTypes)) {
continue; continue;
} }
$search = $this->searchEntityTable($searchOpts, $entityType, $page, $count, $action); $search = $this->searchEntityTable($searchOpts, $entityType, $page, $count, $action);
/** @var int $entityTotal */
$entityTotal = $this->searchEntityTable($searchOpts, $entityType, $page, $count, $action, true); $entityTotal = $this->searchEntityTable($searchOpts, $entityType, $page, $count, $action, true);
if ($entityTotal > $page * $count) {
if ($entityTotal > ($page * $count)) {
$hasMore = true; $hasMore = true;
} }
$total += $entityTotal; $total += $entityTotal;
$results = $results->merge($search); $results = $results->merge($search);
} }

View File

@ -5,6 +5,7 @@ namespace BookStack\Entities\Tools;
use BookStack\Entities\EntityProvider; use BookStack\Entities\EntityProvider;
use BookStack\Entities\Models\Book; use BookStack\Entities\Models\Book;
use BookStack\Entities\Models\Bookshelf; use BookStack\Entities\Models\Bookshelf;
use BookStack\Entities\Models\Page;
use Illuminate\Support\Collection; use Illuminate\Support\Collection;
class SiblingFetcher class SiblingFetcher
@ -18,18 +19,18 @@ class SiblingFetcher
$entities = []; $entities = [];
// Page in chapter // Page in chapter
if ($entity->isA('page') && $entity->chapter) { if ($entity instanceof Page && $entity->chapter) {
$entities = $entity->chapter->getVisiblePages(); $entities = $entity->chapter->getVisiblePages();
} }
// Page in book or chapter // Page in book or chapter
if (($entity->isA('page') && !$entity->chapter) || $entity->isA('chapter')) { if (($entity instanceof Page && !$entity->chapter) || $entity->isA('chapter')) {
$entities = $entity->book->getDirectChildren(); $entities = $entity->book->getDirectChildren();
} }
// Book // Book
// Gets just the books in a shelf if shelf is in context // Gets just the books in a shelf if shelf is in context
if ($entity->isA('book')) { if ($entity instanceof Book) {
$contextShelf = (new ShelfContext())->getContextualShelfForBook($entity); $contextShelf = (new ShelfContext())->getContextualShelfForBook($entity);
if ($contextShelf) { if ($contextShelf) {
$entities = $contextShelf->visibleBooks()->get(); $entities = $contextShelf->visibleBooks()->get();
@ -38,8 +39,8 @@ class SiblingFetcher
} }
} }
// Shelve // Shelf
if ($entity->isA('bookshelf')) { if ($entity instanceof Bookshelf) {
$entities = Bookshelf::visible()->get(); $entities = Bookshelf::visible()->get();
} }

View File

@ -4,13 +4,14 @@ namespace BookStack\Entities\Tools;
use BookStack\Entities\Models\BookChild; use BookStack\Entities\Models\BookChild;
use BookStack\Interfaces\Sluggable; use BookStack\Interfaces\Sluggable;
use BookStack\Model;
use Illuminate\Support\Str; use Illuminate\Support\Str;
class SlugGenerator class SlugGenerator
{ {
/** /**
* Generate a fresh slug for the given entity. * Generate a fresh slug for the given entity.
* The slug will generated so it does not conflict within the same parent item. * The slug will be generated so that it doesn't conflict within the same parent item.
*/ */
public function generate(Sluggable $model): string public function generate(Sluggable $model): string
{ {
@ -38,6 +39,7 @@ class SlugGenerator
/** /**
* Check if a slug is already in-use for this * Check if a slug is already in-use for this
* type of model within the same parent. * type of model within the same parent.
* @param Sluggable&Model $model
*/ */
protected function slugInUse(string $slug, Sluggable $model): bool protected function slugInUse(string $slug, Sluggable $model): bool
{ {

View File

@ -10,10 +10,7 @@ use BookStack\Exceptions\UserTokenExpiredException;
use BookStack\Exceptions\UserTokenNotFoundException; use BookStack\Exceptions\UserTokenNotFoundException;
use BookStack\Http\Controllers\Controller; use BookStack\Http\Controllers\Controller;
use Exception; use Exception;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request; use Illuminate\Http\Request;
use Illuminate\Routing\Redirector;
use Illuminate\View\View;
class ConfirmEmailController extends Controller class ConfirmEmailController extends Controller
{ {
@ -57,25 +54,18 @@ class ConfirmEmailController extends Controller
/** /**
* Confirms an email via a token and logs the user into the system. * Confirms an email via a token and logs the user into the system.
* *
* @param $token
*
* @throws ConfirmationEmailException * @throws ConfirmationEmailException
* @throws Exception * @throws Exception
*
* @return RedirectResponse|Redirector
*/ */
public function confirm($token) public function confirm(string $token)
{ {
try { try {
$userId = $this->emailConfirmationService->checkTokenAndGetUserId($token); $userId = $this->emailConfirmationService->checkTokenAndGetUserId($token);
} catch (Exception $exception) { } catch (UserTokenNotFoundException $exception) {
if ($exception instanceof UserTokenNotFoundException) {
$this->showErrorNotification(trans('errors.email_confirmation_invalid')); $this->showErrorNotification(trans('errors.email_confirmation_invalid'));
return redirect('/register'); return redirect('/register');
} } catch (UserTokenExpiredException $exception) {
if ($exception instanceof UserTokenExpiredException) {
$user = $this->userRepo->getById($exception->userId); $user = $this->userRepo->getById($exception->userId);
$this->emailConfirmationService->sendConfirmation($user); $this->emailConfirmationService->sendConfirmation($user);
$this->showErrorNotification(trans('errors.email_confirmation_expired')); $this->showErrorNotification(trans('errors.email_confirmation_expired'));
@ -83,9 +73,6 @@ class ConfirmEmailController extends Controller
return redirect('/register/confirm'); return redirect('/register/confirm');
} }
throw $exception;
}
$user = $this->userRepo->getById($userId); $user = $this->userRepo->getById($userId);
$user->email_confirmed = true; $user->email_confirmed = true;
$user->save(); $user->save();
@ -99,10 +86,6 @@ class ConfirmEmailController extends Controller
/** /**
* Resend the confirmation email. * Resend the confirmation email.
*
* @param Request $request
*
* @return View
*/ */
public function resend(Request $request) public function resend(Request $request)
{ {

View File

@ -165,7 +165,7 @@ abstract class Controller extends BaseController
/** /**
* Log an activity in the system. * Log an activity in the system.
* *
* @param string|Loggable * @param $detail string|Loggable
*/ */
protected function logActivity(string $type, $detail = ''): void protected function logActivity(string $type, $detail = ''): void
{ {

View File

@ -66,7 +66,7 @@ class FavouriteController extends Controller
* @throws \Illuminate\Validation\ValidationException * @throws \Illuminate\Validation\ValidationException
* @throws \Exception * @throws \Exception
*/ */
protected function getValidatedModelFromRequest(Request $request): Favouritable protected function getValidatedModelFromRequest(Request $request): Entity
{ {
$modelInfo = $this->validate($request, [ $modelInfo = $this->validate($request, [
'type' => ['required', 'string'], 'type' => ['required', 'string'],

View File

@ -12,7 +12,7 @@ class CheckUserHasPermission
* *
* @param \Illuminate\Http\Request $request * @param \Illuminate\Http\Request $request
* @param \Closure $next * @param \Closure $next
* @param $permission * @param string $permission
* *
* @return mixed * @return mixed
*/ */

View File

@ -2,18 +2,12 @@
namespace BookStack\Interfaces; namespace BookStack\Interfaces;
use Illuminate\Database\Eloquent\Builder;
/** /**
* Interface Sluggable.
*
* Assigned to models that can have slugs. * Assigned to models that can have slugs.
* Must have the below properties. * Must have the below properties.
* *
* @property int $id * @property int $id
* @property string $name * @property string $name
*
* @method Builder newQuery
*/ */
interface Sluggable interface Sluggable
{ {

View File

@ -9,12 +9,9 @@ class Model extends EloquentModel
/** /**
* Provides public access to get the raw attribute value from the model. * Provides public access to get the raw attribute value from the model.
* Used in areas where no mutations are required but performance is critical. * Used in areas where no mutations are required but performance is critical.
*
* @param $key
*
* @return mixed * @return mixed
*/ */
public function getRawAttribute($key) public function getRawAttribute(string $key)
{ {
return parent::getAttributeFromArray($key); return parent::getAttributeFromArray($key);
} }

View File

@ -6,8 +6,8 @@ use BookStack\Auth\User;
use Illuminate\Database\Eloquent\Relations\BelongsTo; use Illuminate\Database\Eloquent\Relations\BelongsTo;
/** /**
* @property int created_by * @property int $created_by
* @property int updated_by * @property int $updated_by
*/ */
trait HasCreatorAndUpdater trait HasCreatorAndUpdater
{ {

View File

@ -6,7 +6,7 @@ use BookStack\Auth\User;
use Illuminate\Database\Eloquent\Relations\BelongsTo; use Illuminate\Database\Eloquent\Relations\BelongsTo;
/** /**
* @property int owned_by * @property int $owned_by
*/ */
trait HasOwner trait HasOwner
{ {

View File

@ -236,7 +236,7 @@ class ImageRepo
->get(['id', 'name', 'slug', 'book_id']); ->get(['id', 'name', 'slug', 'book_id']);
foreach ($pages as $page) { foreach ($pages as $page) {
$page->url = $page->getUrl(); $page->setAttribute('url', $page->getUrl());
} }
return $pages->all(); return $pages->all();

View File

@ -8,6 +8,7 @@ use Exception;
use Illuminate\Contracts\Cache\Repository as Cache; use Illuminate\Contracts\Cache\Repository as Cache;
use Illuminate\Contracts\Filesystem\FileNotFoundException; use Illuminate\Contracts\Filesystem\FileNotFoundException;
use Illuminate\Contracts\Filesystem\Filesystem as Storage; use Illuminate\Contracts\Filesystem\Filesystem as Storage;
use Illuminate\Filesystem\FilesystemAdapter;
use Illuminate\Filesystem\FilesystemManager; use Illuminate\Filesystem\FilesystemManager;
use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\Log;
@ -436,10 +437,12 @@ class ImageService
*/ */
public function pathExistsInLocalSecure(string $imagePath): bool public function pathExistsInLocalSecure(string $imagePath): bool
{ {
/** @var FilesystemAdapter $disk */
$disk = $this->getStorageDisk('gallery'); $disk = $this->getStorageDisk('gallery');
// Check local_secure is active // Check local_secure is active
return $this->usingSecureImages() return $this->usingSecureImages()
&& $disk instanceof FilesystemAdapter
// Check the image file exists // Check the image file exists
&& $disk->exists($imagePath) && $disk->exists($imagePath)
// Check the file is likely an image file // Check the file is likely an image file

View File

@ -4,6 +4,7 @@ namespace BookStack\Util;
use DOMAttr; use DOMAttr;
use DOMDocument; use DOMDocument;
use DOMElement;
use DOMNodeList; use DOMNodeList;
use DOMXPath; use DOMXPath;
@ -92,7 +93,9 @@ class HtmlContentFilter
/** @var DOMAttr $attr */ /** @var DOMAttr $attr */
foreach ($attrs as $attr) { foreach ($attrs as $attr) {
$attrName = $attr->nodeName; $attrName = $attr->nodeName;
$attr->parentNode->removeAttribute($attrName); /** @var DOMElement $parentNode */
$parentNode = $attr->parentNode;
$parentNode->removeAttribute($attrName);
} }
} }
} }

View File

@ -15,7 +15,7 @@ parameters:
- bootstrap/phpstan.php - bootstrap/phpstan.php
ignoreErrors: ignoreErrors:
# - '#Unsafe usage of new static#' # - '#PHPDoc tag @throws with type .*?Psr\\SimpleCache\\InvalidArgumentException.*? is not subtype of Throwable#'
excludePaths: excludePaths:
- ./Config/**/*.php - ./Config/**/*.php