diff --git a/app/Api/V1/Controllers/BudgetLimitController.php b/app/Api/V1/Controllers/BudgetLimitController.php index e875a475f5..16cf1d095a 100644 --- a/app/Api/V1/Controllers/BudgetLimitController.php +++ b/app/Api/V1/Controllers/BudgetLimitController.php @@ -23,7 +23,7 @@ declare(strict_types=1); namespace FireflyIII\Api\V1\Controllers; -use Carbon\Carbon; + use FireflyIII\Api\V1\Requests\BudgetLimitRequest; use FireflyIII\Exceptions\FireflyException; use FireflyIII\Models\BudgetLimit; @@ -34,13 +34,13 @@ use Illuminate\Http\JsonResponse; use Illuminate\Http\Request; use Illuminate\Pagination\LengthAwarePaginator; use Illuminate\Support\Collection; -use InvalidArgumentException; + use League\Fractal\Manager; use League\Fractal\Pagination\IlluminatePaginatorAdapter; use League\Fractal\Resource\Collection as FractalCollection; use League\Fractal\Resource\Item; use League\Fractal\Serializer\JsonApiSerializer; -use Log; + /** * Class BudgetLimitController. diff --git a/app/Console/Commands/CreateImport.php b/app/Console/Commands/CreateImport.php index 8831fa56b9..74910381e2 100644 --- a/app/Console/Commands/CreateImport.php +++ b/app/Console/Commands/CreateImport.php @@ -265,8 +265,8 @@ class CreateImport extends Command */ private function validArguments(): bool { - $file = $this->argument('file'); - $configuration = $this->argument('configuration'); + $file = (string)$this->argument('file'); + $configuration = (string)$this->argument('configuration'); $cwd = getcwd(); $validTypes = config('import.options.file.import_formats'); $type = strtolower($this->option('type')); diff --git a/app/Console/Commands/DecryptAttachment.php b/app/Console/Commands/DecryptAttachment.php index 75cfaf6329..dfa57386e5 100644 --- a/app/Console/Commands/DecryptAttachment.php +++ b/app/Console/Commands/DecryptAttachment.php @@ -63,8 +63,8 @@ class DecryptAttachment extends Command $repository = app(AttachmentRepositoryInterface::class); $attachmentId = (int)$this->argument('id'); $attachment = $repository->findWithoutUser($attachmentId); - $attachmentName = trim($this->argument('name')); - $storagePath = realpath(trim($this->argument('directory'))); + $attachmentName = trim((string)$this->argument('name')); + $storagePath = realpath(trim((string)$this->argument('directory'))); if (null === $attachment) { $this->error(sprintf('No attachment with id #%d', $attachmentId)); Log::error(sprintf('DecryptAttachment: No attachment with id #%d', $attachmentId)); diff --git a/app/Console/Commands/Import.php b/app/Console/Commands/Import.php index 5d6d853f59..7fad01c15e 100644 --- a/app/Console/Commands/Import.php +++ b/app/Console/Commands/Import.php @@ -62,7 +62,7 @@ class Import extends Command public function handle(): int { Log::debug('Start start-import command'); - $jobKey = $this->argument('key'); + $jobKey = (string)$this->argument('key'); $job = ImportJob::where('key', $jobKey)->first(); if (null === $job) { $this->errorLine(sprintf('No job found with key "%s"', $jobKey)); diff --git a/app/Console/Commands/UpgradeFireflyInstructions.php b/app/Console/Commands/UpgradeFireflyInstructions.php index 54695221c4..d2e4730204 100644 --- a/app/Console/Commands/UpgradeFireflyInstructions.php +++ b/app/Console/Commands/UpgradeFireflyInstructions.php @@ -48,10 +48,10 @@ class UpgradeFireflyInstructions extends Command */ public function handle(): int { - if ('update' === $this->argument('task')) { + if ('update' === (string)$this->argument('task')) { $this->updateInstructions(); } - if ('install' === $this->argument('task')) { + if ('install' === (string)$this->argument('task')) { $this->installInstructions(); } return 0; diff --git a/app/Factory/AccountFactory.php b/app/Factory/AccountFactory.php index a3e7f3d4a3..aeb9b62b3b 100644 --- a/app/Factory/AccountFactory.php +++ b/app/Factory/AccountFactory.php @@ -189,7 +189,7 @@ class AccountFactory } if (null === $result) { /** @var string $type */ - $type = (string)config('firefly.accountTypeByIdentifier.' . (string)$accountType); + $type = (string)config('firefly.accountTypeByIdentifier.' . $accountType); $result = AccountType::whereType($type)->first(); if (null === $result && null !== $accountType) { // try as full name: diff --git a/app/Handlers/Events/VersionCheckEventHandler.php b/app/Handlers/Events/VersionCheckEventHandler.php index 3955de9098..072983d8c4 100644 --- a/app/Handlers/Events/VersionCheckEventHandler.php +++ b/app/Handlers/Events/VersionCheckEventHandler.php @@ -24,14 +24,14 @@ declare(strict_types=1); namespace FireflyIII\Handlers\Events; -use Carbon\Carbon; + use FireflyConfig; use FireflyIII\Events\RequestedVersionCheckStatus; -use FireflyIII\Exceptions\FireflyException; + use FireflyIII\Helpers\Update\UpdateTrait; use FireflyIII\Repositories\User\UserRepositoryInterface; -use FireflyIII\Services\Github\Object\Release; -use FireflyIII\Services\Github\Request\UpdateRequest; + + use FireflyIII\User; use Log; @@ -66,7 +66,6 @@ class VersionCheckEventHandler return; } - $permission = FireflyConfig::get('permission_update_check', -1); $lastCheckTime = FireflyConfig::get('last_update_check', time()); $now = time(); $diff = $now - $lastCheckTime->data; diff --git a/app/Http/Controllers/Account/ReconcileController.php b/app/Http/Controllers/Account/ReconcileController.php index 9e16cb589a..e43276c4dd 100644 --- a/app/Http/Controllers/Account/ReconcileController.php +++ b/app/Http/Controllers/Account/ReconcileController.php @@ -185,7 +185,7 @@ class ReconcileController extends Controller if (TransactionType::RECONCILIATION !== $journal->transactionType->type) { return redirect(route('transactions.show', [$journal->id])); } - $subTitle = (string)trans('firefly.reconciliation') . ' "' . $journal->description . '"'; + $subTitle = trans('firefly.reconciliation') . ' "' . $journal->description . '"'; // get main transaction: $transaction = $this->repository->getAssetTransaction($journal); diff --git a/app/Http/Controllers/AttachmentController.php b/app/Http/Controllers/AttachmentController.php index 272b7a3f3b..443ad3e62a 100644 --- a/app/Http/Controllers/AttachmentController.php +++ b/app/Http/Controllers/AttachmentController.php @@ -146,8 +146,9 @@ class AttachmentController extends Controller $this->rememberPreviousUri('attachments.edit.uri'); } $request->session()->forget('attachments.edit.fromUpdate'); - - $preFilled['notes'] = $this->repository->getNoteText($attachment); + $preFilled = [ + 'notes' => $this->repository->getNoteText($attachment), + ]; $request->session()->flash('preFilled', $preFilled); return view('attachments.edit', compact('attachment', 'subTitleIcon', 'subTitle')); diff --git a/app/Http/Controllers/Category/NoCategoryController.php b/app/Http/Controllers/Category/NoCategoryController.php index d50c88190b..59b03f4a1f 100644 --- a/app/Http/Controllers/Category/NoCategoryController.php +++ b/app/Http/Controllers/Category/NoCategoryController.php @@ -29,7 +29,7 @@ use FireflyIII\Helpers\Collector\JournalCollectorInterface; use FireflyIII\Helpers\Filter\InternalTransferFilter; use FireflyIII\Http\Controllers\Controller; use FireflyIII\Models\TransactionType; -use FireflyIII\Repositories\Category\CategoryRepositoryInterface; + use FireflyIII\Repositories\Journal\JournalRepositoryInterface; use FireflyIII\Support\CacheProperties; use Illuminate\Http\Request; diff --git a/app/Http/Controllers/CurrencyController.php b/app/Http/Controllers/CurrencyController.php index 927bc5880c..311f7a6681 100644 --- a/app/Http/Controllers/CurrencyController.php +++ b/app/Http/Controllers/CurrencyController.php @@ -22,7 +22,7 @@ declare(strict_types=1); namespace FireflyIII\Http\Controllers; -use Cache; + use FireflyIII\Http\Requests\CurrencyFormRequest; use FireflyIII\Models\TransactionCurrency; use FireflyIII\Repositories\Currency\CurrencyRepositoryInterface; diff --git a/app/Http/Controllers/HelpController.php b/app/Http/Controllers/HelpController.php index 92323afb4c..91033e1eb2 100644 --- a/app/Http/Controllers/HelpController.php +++ b/app/Http/Controllers/HelpController.php @@ -78,7 +78,7 @@ class HelpController extends Controller private function getHelpText(string $route, string $language): string { // get language and default variables. - $content = '
' . (string)trans('firefly.route_has_no_help') . '
'; + $content = '' . trans('firefly.route_has_no_help') . '
'; // if no such route, log error and return default text. if (!$this->help->hasRoute($route)) { @@ -120,6 +120,6 @@ class HelpController extends Controller return $content; } - return '' . (string)trans('firefly.route_has_no_help') . '
'; + return '' . trans('firefly.route_has_no_help') . '
'; } } diff --git a/app/Http/Controllers/Import/JobStatusController.php b/app/Http/Controllers/Import/JobStatusController.php index 57e96cee6e..62adfeb7eb 100644 --- a/app/Http/Controllers/Import/JobStatusController.php +++ b/app/Http/Controllers/Import/JobStatusController.php @@ -97,8 +97,8 @@ class JobStatusController extends Controller if ('file' === $importJob->provider) { $json['download_config'] = true; $json['download_config_text'] - = (string)trans('import.should_download_config', ['route' => route('import.job.download', [$importJob->key])]) . ' ' - . (string)trans('import.share_config_file'); + = trans('import.should_download_config', ['route' => route('import.job.download', [$importJob->key])]) . ' ' + . trans('import.share_config_file'); } // if count is zero: diff --git a/app/Import/Storage/ImportArrayStorage.php b/app/Import/Storage/ImportArrayStorage.php index 666593e238..1b04ca8f12 100644 --- a/app/Import/Storage/ImportArrayStorage.php +++ b/app/Import/Storage/ImportArrayStorage.php @@ -463,6 +463,7 @@ class ImportArrayStorage foreach ($transaction['transactions'] as $current) { // get the amount: + /** @noinspection UnnecessaryCastingInspection */ $amount = (string)($current['amount'] ?? '0'); if (bccomp($amount, '0') === -1) { $amount = bcmul($amount, '-1'); // @codeCoverageIgnore diff --git a/app/Models/Account.php b/app/Models/Account.php index 00be2897de..ba5aef5da0 100644 --- a/app/Models/Account.php +++ b/app/Models/Account.php @@ -31,6 +31,7 @@ use Illuminate\Database\Eloquent\Builder as EloquentBuilder; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Relations\BelongsTo; use Illuminate\Database\Eloquent\Relations\HasMany; +use Illuminate\Database\Eloquent\Relations\MorphMany; use Illuminate\Database\Eloquent\SoftDeletes; use Illuminate\Support\Collection; use Log; @@ -200,7 +201,7 @@ class Account extends Model * @codeCoverageIgnore * Get all of the notes. */ - public function notes() + public function notes(): MorphMany { return $this->morphMany(Note::class, 'noteable'); } diff --git a/app/Models/Attachment.php b/app/Models/Attachment.php index 43d12b7f15..591f2dfa71 100644 --- a/app/Models/Attachment.php +++ b/app/Models/Attachment.php @@ -27,6 +27,7 @@ use Crypt; use FireflyIII\User; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Relations\BelongsTo; +use Illuminate\Database\Eloquent\Relations\MorphMany; use Illuminate\Database\Eloquent\Relations\MorphTo; use Illuminate\Database\Eloquent\SoftDeletes; use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; @@ -180,7 +181,7 @@ class Attachment extends Model * @codeCoverageIgnore * Get all of the notes. */ - public function notes() + public function notes(): MorphMany { return $this->morphMany(Note::class, 'noteable'); } diff --git a/app/Models/Bill.php b/app/Models/Bill.php index 99a30828e5..f0b0ce6711 100644 --- a/app/Models/Bill.php +++ b/app/Models/Bill.php @@ -28,6 +28,7 @@ use FireflyIII\User; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Relations\BelongsTo; use Illuminate\Database\Eloquent\Relations\HasMany; +use Illuminate\Database\Eloquent\Relations\MorphMany; use Illuminate\Database\Eloquent\SoftDeletes; use Illuminate\Support\Collection; use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; @@ -155,7 +156,7 @@ class Bill extends Model * @codeCoverageIgnore * Get all of the notes. */ - public function notes() + public function notes(): MorphMany { return $this->morphMany(Note::class, 'noteable'); } diff --git a/app/Models/Note.php b/app/Models/Note.php index 1e37ef8cc0..ee4accbce0 100644 --- a/app/Models/Note.php +++ b/app/Models/Note.php @@ -24,6 +24,7 @@ namespace FireflyIII\Models; use Carbon\Carbon; use Illuminate\Database\Eloquent\Model; +use Illuminate\Database\Eloquent\Relations\MorphTo; use Illuminate\Database\Eloquent\SoftDeletes; /** @@ -58,7 +59,7 @@ class Note extends Model * * Get all of the owning noteable models. */ - public function noteable() + public function noteable(): MorphTo { return $this->morphTo(); } diff --git a/app/Models/PiggyBank.php b/app/Models/PiggyBank.php index d6779aef84..7436b5c35c 100644 --- a/app/Models/PiggyBank.php +++ b/app/Models/PiggyBank.php @@ -26,6 +26,7 @@ use Carbon\Carbon; use Crypt; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Relations\BelongsTo; +use Illuminate\Database\Eloquent\Relations\MorphMany; use Illuminate\Database\Eloquent\SoftDeletes; use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; @@ -123,7 +124,7 @@ class PiggyBank extends Model * @codeCoverageIgnore * Get all of the piggy bank's notes. */ - public function notes() + public function notes(): MorphMany { return $this->morphMany(Note::class, 'noteable'); } diff --git a/app/Models/Recurrence.php b/app/Models/Recurrence.php index 7b6743019e..243eece7b6 100644 --- a/app/Models/Recurrence.php +++ b/app/Models/Recurrence.php @@ -28,6 +28,7 @@ use FireflyIII\User; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Relations\BelongsTo; use Illuminate\Database\Eloquent\Relations\HasMany; +use Illuminate\Database\Eloquent\Relations\MorphMany; use Illuminate\Database\Eloquent\SoftDeletes; use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; @@ -112,7 +113,7 @@ class Recurrence extends Model * @codeCoverageIgnore * Get all of the notes. */ - public function notes() + public function notes(): MorphMany { return $this->morphMany(Note::class, 'noteable'); } diff --git a/app/Models/TransactionJournal.php b/app/Models/TransactionJournal.php index eba8e70d3d..77478c8be1 100644 --- a/app/Models/TransactionJournal.php +++ b/app/Models/TransactionJournal.php @@ -30,6 +30,7 @@ use Illuminate\Database\Eloquent\Builder as EloquentBuilder; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Relations\BelongsToMany; use Illuminate\Database\Eloquent\Relations\HasMany; +use Illuminate\Database\Eloquent\Relations\MorphMany; use Illuminate\Database\Eloquent\SoftDeletes; use Illuminate\Support\Collection; use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; @@ -59,6 +60,8 @@ use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; * @property string period_marker * @property Carbon $date * @property string $transaction_type_type + * @property int $id + * @property TransactionType $transactionType * * @SuppressWarnings(PHPMD.TooManyPublicMethods) * @SuppressWarnings(PHPMD.CouplingBetweenObjects) @@ -248,7 +251,7 @@ class TransactionJournal extends Model * @codeCoverageIgnore * Get all of the notes. */ - public function notes() + public function notes(): MorphMany { return $this->morphMany(Note::class, 'noteable'); } diff --git a/app/Models/TransactionJournalLink.php b/app/Models/TransactionJournalLink.php index dad69ba82f..38de517ea4 100644 --- a/app/Models/TransactionJournalLink.php +++ b/app/Models/TransactionJournalLink.php @@ -26,6 +26,7 @@ use Carbon\Carbon; use Crypt; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Relations\BelongsTo; +use Illuminate\Database\Eloquent\Relations\MorphMany; use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; /** @@ -111,7 +112,7 @@ class TransactionJournalLink extends Model * @codeCoverageIgnore * Get all of the notes. */ - public function notes() + public function notes(): MorphMany { return $this->morphMany(Note::class, 'noteable'); } diff --git a/app/Providers/EventServiceProvider.php b/app/Providers/EventServiceProvider.php index fd80ce452f..c775be7825 100644 --- a/app/Providers/EventServiceProvider.php +++ b/app/Providers/EventServiceProvider.php @@ -106,7 +106,7 @@ class EventServiceProvider extends ServiceProvider * @codeCoverageIgnore * Register any events for your application. */ - public function boot() + public function boot(): void { parent::boot(); $this->registerCreateEvents(); diff --git a/app/Providers/SessionServiceProvider.php b/app/Providers/SessionServiceProvider.php index 2f936a0747..9ccdc0c769 100644 --- a/app/Providers/SessionServiceProvider.php +++ b/app/Providers/SessionServiceProvider.php @@ -34,7 +34,7 @@ class SessionServiceProvider extends BaseSessionServiceProvider /** * Register the service provider. */ - public function register() + public function register(): void { $this->registerSessionManager(); diff --git a/app/Repositories/Account/AccountRepositoryInterface.php b/app/Repositories/Account/AccountRepositoryInterface.php index 59e67acfc8..09a0981209 100644 --- a/app/Repositories/Account/AccountRepositoryInterface.php +++ b/app/Repositories/Account/AccountRepositoryInterface.php @@ -24,8 +24,8 @@ namespace FireflyIII\Repositories\Account; use Carbon\Carbon; use FireflyIII\Models\Account; -use FireflyIII\Models\AccountType; -use FireflyIII\Models\Note; + + use FireflyIII\Models\TransactionJournal; use FireflyIII\User; use Illuminate\Support\Collection; diff --git a/app/Repositories/Attachment/AttachmentRepository.php b/app/Repositories/Attachment/AttachmentRepository.php index caad252875..1d5d55d7bc 100644 --- a/app/Repositories/Attachment/AttachmentRepository.php +++ b/app/Repositories/Attachment/AttachmentRepository.php @@ -31,6 +31,7 @@ use FireflyIII\Helpers\Attachments\AttachmentHelperInterface; use FireflyIII\Models\Attachment; use FireflyIII\Models\Note; use FireflyIII\User; +use Illuminate\Contracts\Filesystem\FileNotFoundException; use Illuminate\Support\Collection; use Log; use Storage; @@ -81,6 +82,7 @@ class AttachmentRepository implements AttachmentRepositoryInterface /** * @param int $attachmentId + * * @return Attachment|null */ public function findWithoutUser(int $attachmentId): ?Attachment @@ -119,8 +121,6 @@ class AttachmentRepository implements AttachmentRepositoryInterface * @param Attachment $attachment * * @return string - * - * @throws \Illuminate\Contracts\Encryption\DecryptException */ public function getContent(Attachment $attachment): string { @@ -130,7 +130,12 @@ class AttachmentRepository implements AttachmentRepositoryInterface $content = ''; if ($disk->exists($file)) { - $content = Crypt::decrypt($disk->get($file)); + try { + $content = Crypt::decrypt($disk->get($file)); + } catch (FileNotFoundException $e) { + Log::debug(sprintf('File not found: %e', $e->getMessage())); + $content = false; + } } if (\is_bool($content)) { Log::error(sprintf('Attachment #%d may be corrupted: the content could not be decrypted.', $attachment->id)); diff --git a/app/Repositories/ExportJob/ExportJobRepository.php b/app/Repositories/ExportJob/ExportJobRepository.php index ec2e0c61a7..49c12086ff 100644 --- a/app/Repositories/ExportJob/ExportJobRepository.php +++ b/app/Repositories/ExportJob/ExportJobRepository.php @@ -25,6 +25,7 @@ namespace FireflyIII\Repositories\ExportJob; use Carbon\Carbon; use FireflyIII\Models\ExportJob; use FireflyIII\User; +use Illuminate\Contracts\Filesystem\FileNotFoundException; use Illuminate\Support\Str; use Log; use Storage; @@ -120,6 +121,7 @@ class ExportJobRepository implements ExportJobRepositoryInterface /** * @param string $key + * * @return ExportJob|null */ public function findByKey(string $key): ?ExportJob @@ -137,14 +139,19 @@ class ExportJobRepository implements ExportJobRepositoryInterface * @param ExportJob $job * * @return string - * */ public function getContent(ExportJob $job): string { - $disk = Storage::disk('export'); - $file = $job->key . '.zip'; + $disk = Storage::disk('export'); + $file = $job->key . '.zip'; + $content = ''; + try { + $content = $disk->get($file); + } catch (FileNotFoundException $e) { + Log::warning(sprintf('File not found: %s', $e->getMessage())); + } - return $disk->get($file); + return $content; } /** diff --git a/app/Repositories/Journal/JournalRepositoryInterface.php b/app/Repositories/Journal/JournalRepositoryInterface.php index 4f2eccf58b..6b26aaa30a 100644 --- a/app/Repositories/Journal/JournalRepositoryInterface.php +++ b/app/Repositories/Journal/JournalRepositoryInterface.php @@ -25,7 +25,7 @@ namespace FireflyIII\Repositories\Journal; use Carbon\Carbon; use FireflyIII\Exceptions\FireflyException; use FireflyIII\Models\Account; -use FireflyIII\Models\Note; + use FireflyIII\Models\Transaction; use FireflyIII\Models\TransactionJournal; use FireflyIII\Models\TransactionJournalMeta; diff --git a/app/Rules/BelongsUser.php b/app/Rules/BelongsUser.php index b873b18fe2..6dc8113d4d 100644 --- a/app/Rules/BelongsUser.php +++ b/app/Rules/BelongsUser.php @@ -65,8 +65,11 @@ class BelongsUser implements Rule * * @return bool * @throws FireflyException + * + * @SuppressWarnings(PHPMD.CyclomaticComplexity) + * @SuppressWarnings(PHPMD.ExcessiveMethodLength) */ - public function passes($attribute, $value) + public function passes($attribute, $value): bool { $attribute = $this->parseAttribute($attribute); if (!auth()->check()) { @@ -75,48 +78,22 @@ class BelongsUser implements Rule $attribute = (string)$attribute; switch ($attribute) { case 'piggy_bank_id': - $count = PiggyBank::leftJoin('accounts', 'accounts.id', '=', 'piggy_banks.account_id') - ->where('piggy_banks.id', '=', (int)$value) - ->where('accounts.user_id', '=', auth()->user()->id)->count(); - - return $count === 1; - break; + return $this->validatePiggyBankId((int)$value); case 'piggy_bank_name': - $count = $this->countField(PiggyBank::class, 'name', $value); - - return $count === 1; - break; + return $this->validatePiggyBankName($value); case 'bill_id': - $count = Bill::where('id', '=', (int)$value)->where('user_id', '=', auth()->user()->id)->count(); - - return $count === 1; + return $this->validateBillId((int)$value); case 'bill_name': - $count = $this->countField(Bill::class, 'name', $value); - - return $count === 1; - break; + return $this->validateBillName($value); case 'budget_id': - $count = Budget::where('id', '=', (int)$value)->where('user_id', '=', auth()->user()->id)->count(); - - return $count === 1; - break; + return $this->validateBudgetId((int)$value); case 'category_id': - $count = Category::where('id', '=', (int)$value)->where('user_id', '=', auth()->user()->id)->count(); - - return $count === 1; - break; + return $this->validateCategoryId((int)$value); case 'budget_name': - $count = $this->countField(Budget::class, 'name', $value); - - return $count === 1; - break; + return $this->validateBudgetName($value); case 'source_id': case 'destination_id': - $count = Account::where('id', '=', (int)$value)->where('user_id', '=', auth()->user()->id)->count(); - - return $count === 1; - break; - + return $this->validateAccountId((int)$value); default: throw new FireflyException(sprintf('Rule BelongUser cannot handle "%s"', $attribute)); // @codeCoverageIgnore } @@ -128,18 +105,20 @@ class BelongsUser implements Rule * @param string $value * * @return int + * + * @SuppressWarnings(PHPMD.CyclomaticComplexity) */ protected function countField(string $class, string $field, string $value): int { + $objects = []; // get all objects belonging to user: - switch ($class) { - case PiggyBank::class: - $objects = PiggyBank::leftJoin('accounts', 'accounts.id', '=', 'piggy_banks.account_id') - ->where('accounts.user_id', '=', auth()->user()->id)->get(['piggy_banks.*']); - break; - default: - $objects = $class::where('user_id', '=', auth()->user()->id)->get(); - break; + if (PiggyBank::class === $class) { + $objects = PiggyBank::leftJoin('accounts', 'accounts.id', '=', 'piggy_banks.account_id') + ->where('accounts.user_id', '=', auth()->user()->id)->get(['piggy_banks.*']); + + } + if (PiggyBank::class !== $class) { + $objects = $class::where('user_id', '=', auth()->user()->id)->get(); } $count = 0; foreach ($objects as $object) { @@ -159,13 +138,111 @@ class BelongsUser implements Rule private function parseAttribute(string $attribute): string { $parts = explode('.', $attribute); - if (\count($parts) === 1) { + if (1 === \count($parts)) { return $attribute; } - if (\count($parts) === 3) { + if (3 === \count($parts)) { return $parts[2]; } return $attribute; // @codeCoverageIgnore } + + /** + * @param int $value + * + * @return bool + */ + private function validateAccountId(int $value): bool + { + $count = Account::where('id', '=', (int)$value)->where('user_id', '=', auth()->user()->id)->count(); + + return 1 === $count; + } + + /** + * @param int $value + * + * @return bool + */ + private function validateBillId(int $value): bool + { + $count = Bill::where('id', '=', $value)->where('user_id', '=', auth()->user()->id)->count(); + + return 1 === $count; + } + + /** + * @param string $value + * + * @return bool + */ + private function validateBillName(string $value): bool + { + $count = $this->countField(Bill::class, 'name', $value); + + return 1 === $count; + } + + /** + * @param int $value + * + * @return bool + */ + private function validateBudgetId(int $value): bool + { + $count = Budget::where('id', '=', $value)->where('user_id', '=', auth()->user()->id)->count(); + + return 1 === $count; + } + + /** + * @param string $value + * + * @return bool + */ + private function validateBudgetName(string $value): bool + { + $count = $this->countField(Budget::class, 'name', $value); + + return 1 === $count; + } + + /** + * @param int $value + * + * @return bool + */ + private function validateCategoryId(int $value): bool + { + $count = Category::where('id', '=', $value)->where('user_id', '=', auth()->user()->id)->count(); + + return 1 === $count; + } + + /** + * @param int $value + * + * @return bool + */ + private function validatePiggyBankId(int $value): bool + { + $count = PiggyBank::leftJoin('accounts', 'accounts.id', '=', 'piggy_banks.account_id') + ->where('piggy_banks.id', '=', $value) + ->where('accounts.user_id', '=', auth()->user()->id)->count(); + + return 1 === $count; + } + + /** + * @param string $value + * + * @return bool + */ + private function validatePiggyBankName(string $value): bool + { + $count = $this->countField(PiggyBank::class, 'name', $value); + + return 1 === $count; + } } diff --git a/app/Rules/IsAssetAccountId.php b/app/Rules/IsAssetAccountId.php index 14f2defc0b..9a59f823ee 100644 --- a/app/Rules/IsAssetAccountId.php +++ b/app/Rules/IsAssetAccountId.php @@ -49,6 +49,8 @@ class IsAssetAccountId implements Rule * @param mixed $value * * @return bool + * + * @SuppressWarnings(PHPMD.UnusedFormalParameter) */ public function passes($attribute, $value): bool { diff --git a/app/Rules/IsValidAttachmentModel.php b/app/Rules/IsValidAttachmentModel.php index 99ceb61f78..f34da76724 100644 --- a/app/Rules/IsValidAttachmentModel.php +++ b/app/Rules/IsValidAttachmentModel.php @@ -24,7 +24,6 @@ declare(strict_types=1); namespace FireflyIII\Rules; -use FireflyIII\Exceptions\FireflyException; use FireflyIII\Models\TransactionJournal; use FireflyIII\Repositories\Journal\JournalRepositoryInterface; use Illuminate\Contracts\Validation\Rule; @@ -64,25 +63,25 @@ class IsValidAttachmentModel implements Rule * @param mixed $value * * @return bool - * @throws FireflyException + * + * @SuppressWarnings(PHPMD.UnusedFormalParameter) */ public function passes($attribute, $value): bool { if (!auth()->check()) { return false; } - $user = auth()->user(); - switch ($this->model) { - default: - throw new FireflyException(sprintf('Model "%s" cannot be validated.', $this->model)); - case TransactionJournal::class: - /** @var JournalRepositoryInterface $repository */ - $repository = app(JournalRepositoryInterface::class); - $repository->setUser($user); - $result = $repository->findNull((int)$value); - return null !== $result; - break; + + if (TransactionJournal::class === $this->model) { + $repository = app(JournalRepositoryInterface::class); + $user = auth()->user(); + $repository->setUser($user); + $result = $repository->findNull((int)$value); + + return null !== $result; } + + return false; } } diff --git a/app/Rules/UniqueIban.php b/app/Rules/UniqueIban.php index a710ae78ad..292746f40d 100644 --- a/app/Rules/UniqueIban.php +++ b/app/Rules/UniqueIban.php @@ -23,7 +23,6 @@ declare(strict_types=1); namespace FireflyIII\Rules; -use FireflyIII\Exceptions\FireflyException; use FireflyIII\Models\Account; use FireflyIII\Models\AccountType; use Illuminate\Contracts\Validation\Rule; @@ -57,7 +56,7 @@ class UniqueIban implements Rule * * @return string */ - public function message() + public function message(): string { return (string)trans('validation.unique_iban_for_user'); } @@ -69,9 +68,10 @@ class UniqueIban implements Rule * @param mixed $value * * @return bool - * @throws FireflyException + * @SuppressWarnings(PHPMD.CyclomaticComplexity) + * @SuppressWarnings(PHPMD.UnusedFormalParameter) */ - public function passes($attribute, $value) + public function passes($attribute, $value): bool { if (!auth()->check()) { return true; // @codeCoverageIgnore @@ -79,50 +79,11 @@ class UniqueIban implements Rule if (null === $this->expectedType) { return true; } - $maxCounts = [ - AccountType::ASSET => 0, - AccountType::EXPENSE => 0, - AccountType::REVENUE => 0, - ]; - switch ($this->expectedType) { - case 'asset': - case AccountType::ASSET: - // iban should be unique amongst asset accounts - // should not be in use with expense or revenue accounts. - // ie: must be totally unique. - break; - case 'expense': - case AccountType::EXPENSE: - // should be unique amongst expense and asset accounts. - // may appear once in revenue accounts - $maxCounts[AccountType::REVENUE] = 1; - break; - case 'revenue': - case AccountType::REVENUE: - // should be unique amongst revenue and asset accounts. - // may appear once in expense accounts - $maxCounts[AccountType::EXPENSE] = 1; - break; - default: - - throw new FireflyException(sprintf('UniqueIban cannot handle type "%s"', $this->expectedType)); - } + $maxCounts = $this->getMaxOccurrences(); foreach ($maxCounts as $type => $max) { - $count = 0; - $query = auth()->user() - ->accounts() - ->leftJoin('account_types', 'account_types.id', '=', 'accounts.account_type_id') - ->where('account_types.type', $type); - if (null !== $this->account) { - $query->where('accounts.id', '!=', $this->account->id); - } - $result = $query->get(['accounts.*']); - foreach ($result as $account) { - if ($account->iban === $value) { - $count++; - } - } + $count = $this->countHits($type, $value); + if ($count > $max) { Log::debug( sprintf( @@ -137,4 +98,57 @@ class UniqueIban implements Rule return true; } + + /** + * @param string $type + * @param string $iban + * + * @return int + */ + private function countHits(string $type, string $iban): int + { + $count = 0; + /** @noinspection NullPointerExceptionInspection */ + $query = auth()->user() + ->accounts() + ->leftJoin('account_types', 'account_types.id', '=', 'accounts.account_type_id') + ->where('account_types.type', $type); + if (null !== $this->account) { + $query->where('accounts.id', '!=', $this->account->id); + } + $result = $query->get(['accounts.*']); + foreach ($result as $account) { + if ($account->iban === $iban) { + $count++; + } + } + + return $count; + } + + /** + * @return array + * @SuppressWarnings(PHPMD.CyclomaticComplexity) + */ + private function getMaxOccurrences(): array + { + $maxCounts = [ + AccountType::ASSET => 0, + AccountType::EXPENSE => 0, + AccountType::REVENUE => 0, + ]; + + if ('expense' === $this->expectedType || AccountType::EXPENSE === $this->expectedType) { + // IBAN should be unique amongst expense and asset accounts. + // may appear once in revenue accounts + $maxCounts[AccountType::REVENUE] = 1; + } + if ('revenue' === $this->expectedType || AccountType::EXPENSE === $this->expectedType) { + // IBAN should be unique amongst revenue and asset accounts. + // may appear once in expense accounts + $maxCounts[AccountType::EXPENSE] = 1; + } + + return $maxCounts; + } } diff --git a/app/Rules/ValidRecurrenceRepetitionType.php b/app/Rules/ValidRecurrenceRepetitionType.php index 10affa68c6..403fc9223a 100644 --- a/app/Rules/ValidRecurrenceRepetitionType.php +++ b/app/Rules/ValidRecurrenceRepetitionType.php @@ -48,11 +48,13 @@ class ValidRecurrenceRepetitionType implements Rule * @param mixed $value * * @return bool + * @SuppressWarnings(PHPMD.UnusedFormalParameter) + * @SuppressWarnings(PHPMD.CyclomaticComplexity) */ public function passes($attribute, $value): bool { $value = (string)$value; - if ($value === 'daily') { + if ('daily' === $value) { return true; } //monthly,17 diff --git a/app/Rules/ValidRecurrenceRepetitionValue.php b/app/Rules/ValidRecurrenceRepetitionValue.php index b2177c9606..825321ae75 100644 --- a/app/Rules/ValidRecurrenceRepetitionValue.php +++ b/app/Rules/ValidRecurrenceRepetitionValue.php @@ -27,6 +27,7 @@ namespace FireflyIII\Rules; use Carbon\Carbon; use Illuminate\Contracts\Validation\Rule; use InvalidArgumentException; +use Log; /** * Class ValidRecurrenceRepetitionValue @@ -51,57 +52,103 @@ class ValidRecurrenceRepetitionValue implements Rule * @param mixed $value * * @return bool + * @SuppressWarnings(PHPMD.UnusedFormalParameter) + * @SuppressWarnings(PHPMD.CyclomaticComplexity) */ public function passes($attribute, $value): bool { $value = (string)$value; - if ($value === 'daily') { + if ('daily' === $value) { return true; } if (0 === strpos($value, 'monthly')) { - $dayOfMonth = (int)substr($value, 8); - - return $dayOfMonth > 0 && $dayOfMonth < 32; + return $this->validateMonthly($value); } //ndom,3,7 // nth x-day of the month. if (0 === strpos($value, 'ndom')) { - $parameters = explode(',', substr($value, 5)); - if (\count($parameters) !== 2) { - return false; - } - $nthDay = (int)($parameters[0] ?? 0.0); - $dayOfWeek = (int)($parameters[1] ?? 0.0); - if ($nthDay < 1 || $nthDay > 5) { - return false; - } - - return $dayOfWeek > 0 && $dayOfWeek < 8; + return $this->validateNdom($value); } //weekly,7 if (0 === strpos($value, 'weekly')) { - $dayOfWeek = (int)substr($value, 7); - - return $dayOfWeek > 0 && $dayOfWeek < 8; + return $this->validateWeekly($value); } //yearly,2018-01-01 if (0 === strpos($value, 'yearly')) { - // rest of the string must be valid date: - $dateString = substr($value, 7); - try { - $date = Carbon::createFromFormat('Y-m-d', $dateString); - } catch (InvalidArgumentException $e) { - return false; - } - - return true; + return $this->validateYearly($value); } return false; } + + /** + * @param string $value + * + * @return bool + */ + private function validateMonthly(string $value): bool + { + $dayOfMonth = (int)substr($value, 8); + + return $dayOfMonth > 0 && $dayOfMonth < 32; + } + + /** + * @param string $value + * + * @return bool + * + * @SuppressWarnings(PHPMD.CyclomaticComplexity) + */ + private function validateNdom(string $value): bool + { + $parameters = explode(',', substr($value, 5)); + if (2 !== \count($parameters)) { + return false; + } + $nthDay = (int)($parameters[0] ?? 0.0); + $dayOfWeek = (int)($parameters[1] ?? 0.0); + if ($nthDay < 1 || $nthDay > 5) { + return false; + } + + return $dayOfWeek > 0 && $dayOfWeek < 8; + } + + /** + * @param string $value + * + * @return bool + */ + private function validateWeekly(string $value): bool + { + $dayOfWeek = (int)substr($value, 7); + + return $dayOfWeek > 0 && $dayOfWeek < 8; + } + + /** + * @param string $value + * + * @return bool + */ + private function validateYearly(string $value): bool + { + // rest of the string must be valid date: + $dateString = substr($value, 7); + try { + Carbon::createFromFormat('Y-m-d', $dateString); + } catch (InvalidArgumentException $e) { + Log::debug(sprintf('Could not parse date %s: %s', $dateString, $e->getMessage())); + + return false; + } + + return true; + } } diff --git a/app/Rules/ValidTransactions.php b/app/Rules/ValidTransactions.php index 17a8e714ee..29fd7baaef 100644 --- a/app/Rules/ValidTransactions.php +++ b/app/Rules/ValidTransactions.php @@ -49,7 +49,7 @@ class ValidTransactions implements Rule * * @return string */ - public function message() + public function message(): string { return (string)trans('validation.invalid_selection'); } @@ -61,8 +61,9 @@ class ValidTransactions implements Rule * @param mixed $value * * @return bool + * @SuppressWarnings(PHPMD.UnusedFormalParameter) */ - public function passes($attribute, $value) + public function passes($attribute, $value): bool { Log::debug('In ValidTransactions::passes'); if (!\is_array($value)) { @@ -73,7 +74,7 @@ class ValidTransactions implements Rule $count = Transaction::where('transactions.id', $transactionId) ->leftJoin('accounts', 'accounts.id', '=', 'transactions.account_id') ->where('accounts.user_id', $userId)->count(); - if ($count === 0) { + if (0 === $count) { Log::debug(sprintf('Count for transaction #%d and user #%d is zero! Return FALSE', $transactionId, $userId)); return false; diff --git a/app/Services/Internal/Update/TransactionUpdateService.php b/app/Services/Internal/Update/TransactionUpdateService.php index c2f94d08e3..32c86d8548 100644 --- a/app/Services/Internal/Update/TransactionUpdateService.php +++ b/app/Services/Internal/Update/TransactionUpdateService.php @@ -75,7 +75,8 @@ class TransactionUpdateService $currency = $this->findCurrency($data['currency_id'], $data['currency_code']); $journal = $transaction->transactionJournal; $description = $journal->description === $data['description'] ? null : $data['description']; - + $amount = (string)$data['amount']; + $account = null; // update description: $transaction->description = $description; $foreignAmount = null; @@ -83,7 +84,7 @@ class TransactionUpdateService // this is the source transaction. $type = $this->accountType($journal, 'source'); $account = $this->findAccount($type, $data['source_id'], $data['source_name']); - $amount = app('steam')->negative((string)$data['amount']); + $amount = app('steam')->negative($amount); $foreignAmount = app('steam')->negative((string)$data['foreign_amount']); } @@ -91,7 +92,7 @@ class TransactionUpdateService // this is the destination transaction. $type = $this->accountType($journal, 'destination'); $account = $this->findAccount($type, $data['destination_id'], $data['destination_name']); - $amount = app('steam')->positive((string)$data['amount']); + $amount = app('steam')->positive($amount); $foreignAmount = app('steam')->positive((string)$data['foreign_amount']); } diff --git a/app/Transformers/PiggyBankTransformer.php b/app/Transformers/PiggyBankTransformer.php index 0816fb0f63..897e969b7e 100644 --- a/app/Transformers/PiggyBankTransformer.php +++ b/app/Transformers/PiggyBankTransformer.php @@ -124,8 +124,8 @@ class PiggyBankTransformer extends TransformerAbstract $accountRepos = app(AccountRepositoryInterface::class); $accountRepos->setUser($account->user); $currencyId = (int)$accountRepos->getMetaValue($account, 'currency_id'); - - if ($currencyId === 0) { + $currency = null; + if (0 === $currencyId) { $currency = app('amount')->getDefaultCurrencyByUser($account->user); }