Compare commits

...

11 Commits

Author SHA1 Message Date
github-actions[bot]
dbc0210304 Merge pull request #11044 from firefly-iii/release-1760115302
🤖 Automatically merge the PR into the develop branch.
2025-10-10 18:55:11 +02:00
JC5
a709e224d4 🤖 Auto commit for release 'develop' on 2025-10-10 2025-10-10 18:55:02 +02:00
James Cole
83f3eddf44 Small code changes for @ctrl-f5's PR.
- Dropped some "setParameters" calls if unused in transformer.
- Add correct copyright
- Sprintf instead of string concat
- Small ident changes courtesy of phpstorm.
2025-10-10 18:50:39 +02:00
James Cole
7cfc4c2671 Merge pull request #11039 from ctrl-f5/feat/improve-request-objects
proposal for improved request handling
2025-10-10 18:38:02 +02:00
mergify[bot]
1c6055cb2d Merge branch 'develop' into feat/improve-request-objects 2025-10-10 14:42:25 +00:00
James Cole
4f4576e458 Add option to select date, fix #11042 2025-10-10 16:41:46 +02:00
mergify[bot]
84d3bcbb37 Merge branch 'develop' into feat/improve-request-objects 2025-10-10 11:33:40 +00:00
mergify[bot]
ad67bb80f3 Merge branch 'develop' into feat/improve-request-objects 2025-10-10 11:29:39 +00:00
mergify[bot]
569f553d26 Merge branch 'develop' into feat/improve-request-objects 2025-10-10 06:58:56 +00:00
mergify[bot]
58c76bee94 Merge branch 'develop' into feat/improve-request-objects 2025-10-10 06:46:55 +00:00
Nicky De Maeyer
52f3ec7d3d improved request handling 2025-10-09 15:05:52 +02:00
21 changed files with 489 additions and 212 deletions

View File

@@ -67,6 +67,8 @@ abstract class Controller extends BaseController
protected bool $convertToPrimary = false;
protected TransactionCurrency $primaryCurrency;
/** @deprecated use Request classes */
protected ParameterBag $parameters;
/**
@@ -98,7 +100,8 @@ abstract class Controller extends BaseController
}
/**
* Method to grab all parameters from the URL.
* @deprecated use Request classes
* Method to grab all parameters from the URL
*/
private function getParameters(): ParameterBag
{

View File

@@ -71,45 +71,45 @@ class ShowController extends Controller
public function index(ShowRequest $request): JsonResponse
{
$manager = $this->getManager();
$params = $request->getParameters();
$this->parameters->set('type', $params['type']);
// types to get, page size:
$types = $this->mapAccountTypes($params['type']);
[
'types' => $types,
'page' => $page,
'limit' => $limit,
'offset' => $offset,
'sort' => $sort,
'start' => $start,
'end' => $end,
'date' => $date,
]
= $request->attributes->all();
// get list of accounts. Count it and split it.
$this->repository->resetAccountOrder();
$collection = $this->repository->getAccountsByType($types, $params['sort']);
$collection = $this->repository->getAccountsByType($types, $sort);
$count = $collection->count();
// continue sort:
// TODO if the user sorts on DB dependent field there must be no slice before enrichment, only after.
// TODO still need to figure out how to do this easily.
$accounts = $collection->slice(($this->parameters->get('page') - 1) * $params['limit'], $params['limit']);
// #11007 go to the end of the previous day.
$this->parameters->set('start', $this->parameters->get('start')?->subSecond());
// #11018 also end of the day.
$this->parameters->set('end', $this->parameters->get('end')?->endOfDay());
$accounts = $collection->slice($offset, $limit);
// enrich
/** @var User $admin */
$admin = auth()->user();
$enrichment = new AccountEnrichment();
$enrichment->setSort($params['sort']);
$enrichment->setDate($this->parameters->get('date'));
$enrichment->setStart($this->parameters->get('start'));
$enrichment->setEnd($this->parameters->get('end'));
$enrichment->setSort($sort);
$enrichment->setDate($date);
$enrichment->setStart($start);
$enrichment->setEnd($end);
$enrichment->setUser($admin);
$accounts = $enrichment->enrich($accounts);
// make paginator:
$paginator = new LengthAwarePaginator($accounts, $count, $params['limit'], $this->parameters->get('page'));
$paginator = new LengthAwarePaginator($accounts, $count, $limit, $page);
$paginator->setPath(route('api.v1.accounts.index').$this->buildParams());
/** @var AccountTransformer $transformer */
$transformer = app(AccountTransformer::class);
$transformer->setParameters($this->parameters);
$resource = new FractalCollection($accounts, $transformer, self::RESOURCE_KEY);
$resource->setPaginator(new IlluminatePaginatorAdapter($paginator));
@@ -128,28 +128,23 @@ class ShowController extends Controller
// get list of accounts. Count it and split it.
$this->repository->resetAccountOrder();
$account->refresh();
$manager = $this->getManager();
// #11007 go to the end of the previous day.
$this->parameters->set('start', $this->parameters->get('start')?->subSecond());
// #11018 also end of the day.
$this->parameters->set('end', $this->parameters->get('end')?->endOfDay());
$manager = $this->getManager();
[$start, $end, $date] = $request->attributes->all();
// enrich
/** @var User $admin */
$admin = auth()->user();
$enrichment = new AccountEnrichment();
$enrichment->setDate($this->parameters->get('date'));
$enrichment->setStart($this->parameters->get('start'));
$enrichment->setEnd($this->parameters->get('end'));
$admin = auth()->user();
$enrichment = new AccountEnrichment();
$enrichment->setDate($date);
$enrichment->setStart($start);
$enrichment->setEnd($end);
$enrichment->setUser($admin);
$account = $enrichment->enrichSingle($account);
$account = $enrichment->enrichSingle($account);
/** @var AccountTransformer $transformer */
$transformer = app(AccountTransformer::class);
$transformer->setParameters($this->parameters);
$resource = new Item($account, $transformer, self::RESOURCE_KEY);
$transformer = app(AccountTransformer::class);
$resource = new Item($account, $transformer, self::RESOURCE_KEY);
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', self::CONTENT_TYPE);
}

View File

@@ -25,7 +25,7 @@ declare(strict_types=1);
namespace FireflyIII\Api\V1\Controllers\Models\UserGroup;
use FireflyIII\Api\V1\Controllers\Controller;
use FireflyIII\Api\V1\Requests\Data\DateRequest;
use FireflyIII\Api\V1\Requests\PaginationRequest;
use FireflyIII\Repositories\UserGroup\UserGroupRepositoryInterface;
use FireflyIII\Transformers\UserGroupTransformer;
use Illuminate\Http\JsonResponse;
@@ -52,17 +52,19 @@ class IndexController extends Controller
);
}
public function index(DateRequest $request): JsonResponse
public function index(PaginationRequest $request): JsonResponse
{
$administrations = $this->repository->get();
$pageSize = $this->parameters->get('limit');
[
'page' => $page,
'limit' => $limit,
'offset' => $offset,
] = $request->attributes->all();
$count = $administrations->count();
$administrations = $administrations->slice(($this->parameters->get('page') - 1) * $pageSize, $pageSize);
$paginator = new LengthAwarePaginator($administrations, $count, $pageSize, $this->parameters->get('page'));
$administrations = $administrations->slice($offset, $limit);
$paginator = new LengthAwarePaginator($administrations, $count, $limit, $page);
$transformer = new UserGroupTransformer();
$transformer->setParameters($this->parameters); // give params to transformer
return response()
->json($this->jsonApiList(self::RESOURCE_KEY, $paginator, $transformer))
->header('Content-Type', self::CONTENT_TYPE)

View File

@@ -27,7 +27,7 @@ namespace FireflyIII\Api\V1\Controllers\Summary;
use Carbon\Carbon;
use Exception;
use FireflyIII\Api\V1\Controllers\Controller;
use FireflyIII\Api\V1\Requests\Data\DateRequest;
use FireflyIII\Api\V1\Requests\DateRangeRequest;
use FireflyIII\Enums\AccountTypeEnum;
use FireflyIII\Enums\TransactionTypeEnum;
use FireflyIII\Helpers\Collector\GroupCollectorInterface;
@@ -94,10 +94,10 @@ class BasicController extends Controller
*
* @throws Exception
*/
public function basic(DateRequest $request): JsonResponse
public function basic(DateRangeRequest $request): JsonResponse
{
// parameters for boxes:
$dates = $request->getAll();
$dates = $request->attributes->all();
$start = $dates['start'];
$end = $dates['end'];
$code = $request->get('currency_code');

View File

@@ -0,0 +1,92 @@
<?php
/*
* Copyright (c) 2025 https://github.com/ctrl-f5
*
* This file is part of Firefly III (https://github.com/firefly-iii).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
declare(strict_types=1);
namespace FireflyIII\Api\V1\Requests;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Http\Request;
use Illuminate\Validation\Validator;
use RuntimeException;
abstract class AggregateFormRequest extends ApiRequest
{
/**
* @var ApiRequest[]
*/
protected array $requests = [];
/** @return class-string[] */
abstract protected function getRequests(): array;
public function initialize(array $query = [], array $request = [], array $attributes = [], array $cookies = [], array $files = [], array $server = [], $content = null): void
{
parent::initialize($query, $request, $attributes, $cookies, $files, $server, $content);
// instantiate all subrequests and share current requests' bags with them
foreach ($this->getRequests() as $config) {
$requestClass = is_array($config) ? array_shift($config) : $config;
if (!is_a($requestClass, Request::class, true)) {
throw new RuntimeException('getRequests() must return class-strings of subclasses of Request');
}
$instance = $this->requests[] = new $requestClass();
$instance->request = $this->request;
$instance->query = $this->query;
$instance->attributes = $this->attributes;
$instance->cookies = $this->cookies;
$instance->files = $this->files;
$instance->server = $this->server;
$instance->headers = $this->headers;
if ($instance instanceof ApiRequest) {
$instance->handleConfig(is_array($config) ? $config : []);
}
}
}
public function rules(): array
{
// check all subrequests for rules and combine them
return array_reduce(
$this->requests,
static fn (array $rules, FormRequest $request) => $rules
+ (
method_exists($request, 'rules')
? $request->rules()
: []
),
[],
);
}
public function withValidator(Validator $validator): void
{
// register all subrequests' validators
foreach ($this->requests as $request) {
if (method_exists($request, 'withValidator')) {
$request->withValidator($validator);
}
}
}
}

View File

@@ -0,0 +1,43 @@
<?php
/*
* Copyright (c) 2025 https://github.com/ctrl-f5
*
* This file is part of Firefly III (https://github.com/firefly-iii).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
declare(strict_types=1);
namespace FireflyIII\Api\V1\Requests;
use FireflyIII\Support\Request\ChecksLogin;
use FireflyIII\Support\Request\ConvertsDataTypes;
use Illuminate\Foundation\Http\FormRequest;
class ApiRequest extends FormRequest
{
use ChecksLogin;
use ConvertsDataTypes;
protected string $required = '';
public function handleConfig(array $config): void
{
if (in_array('required', $config, true)) {
$this->required = 'required';
}
}
}

View File

@@ -1,82 +0,0 @@
<?php
/*
* DateRequest.php
* Copyright (c) 2021 james@firefly-iii.org
*
* This file is part of Firefly III (https://github.com/firefly-iii).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
declare(strict_types=1);
namespace FireflyIII\Api\V1\Requests\Data;
use FireflyIII\Exceptions\ValidationException;
use FireflyIII\Support\Request\ChecksLogin;
use FireflyIII\Support\Request\ConvertsDataTypes;
use Illuminate\Foundation\Http\FormRequest;
/**
* Request class for end points that require date parameters.
*
* Class DateRequest
*/
class DateRequest extends FormRequest
{
use ChecksLogin;
use ConvertsDataTypes;
/**
* Get all data from the request.
*/
public function getAll(): array
{
$start = $this->getCarbonDate('start');
$end = $this->getCarbonDate('end');
if (null === $start) {
$start = now()->startOfMonth();
}
if (null === $end) {
$end = now()->endOfMonth();
}
// sanity check on dates:
[$start, $end] = $end < $start ? [$end, $start] : [$start, $end];
$start->startOfDay();
$end->endOfDay();
if ($start->diffInYears($end, true) > 5) {
throw new ValidationException('Date range out of range.');
}
return [
'start' => $start,
'end' => $end,
'date' => $this->getCarbonDate('date'),
];
}
/**
* The rules that the incoming request must be matched against.
*/
public function rules(): array
{
return [
'date' => 'date|after:1970-01-02|before:2038-01-17',
'start' => 'date|after:1970-01-02|before:2038-01-17|before:end|required_with:end',
'end' => 'date|after:1970-01-02|before:2038-01-17|after:start|required_with:start',
];
}
}

View File

@@ -0,0 +1,53 @@
<?php
/*
* Copyright (c) 2025 https://github.com/ctrl-f5
*
* This file is part of Firefly III (https://github.com/firefly-iii).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
declare(strict_types=1);
namespace FireflyIII\Api\V1\Requests;
use Illuminate\Validation\Validator;
class DateRangeRequest extends ApiRequest
{
public function rules(): array
{
return [
'start' => sprintf('date|after:1970-01-02|before:2038-01-17|before:end|required_with:end|', $this->required),
'end' => sprintf('date|after:1970-01-02|before:2038-01-17|after:start|required_with:start|', $this->required),
];
}
public function withValidator(Validator $validator): void
{
$validator->after(
function (Validator $validator): void {
if (!$validator->valid()) {
return;
}
$start = $this->getCarbonDate('start')?->startOfDay();
$end = $this->getCarbonDate('end')?->endOfDay();
$this->attributes->set('start', $start);
$this->attributes->set('end', $end);
}
);
}
}

View File

@@ -0,0 +1,57 @@
<?php
/*
* Copyright (c) 2025 https://github.com/ctrl-f5
*
* This file is part of Firefly III (https://github.com/firefly-iii).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
declare(strict_types=1);
namespace FireflyIII\Api\V1\Requests;
use Illuminate\Validation\Validator;
class DateRequest extends ApiRequest
{
public function rules(): array
{
return [
'date' => 'date|after:1970-01-02|before:2038-01-17|'.$this->required,
];
}
public function withValidator(Validator $validator): void
{
$validator->after(
function (Validator $validator): void {
if (!$validator->valid()) {
return;
}
$date = $this->getCarbonDate('date')?->endOfDay();
// if we also have a range, date must be in that range
$start = $this->attributes->get('start');
$end = $this->attributes->get('end');
if ($date && $start && $end && !$date->between($start, $end)) {
$validator->errors()->add('date', (string)trans('validation.between_date'));
}
$this->attributes->set('date', $date);
}
);
}
}

View File

@@ -0,0 +1,57 @@
<?php
declare(strict_types=1);
/*
* AccountTypeApiRequest.php
* Copyright (c) 2025 https://github.com/ctrl-f5
*
* This file is part of Firefly III (https://github.com/firefly-iii).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
namespace FireflyIII\Api\V1\Requests\Models\Account;
use FireflyIII\Api\V1\Requests\ApiRequest;
use FireflyIII\Support\Http\Api\AccountFilter;
use Illuminate\Validation\Validator;
class AccountTypeApiRequest extends ApiRequest
{
use AccountFilter;
public function rules(): array
{
return [
'type' => sprintf('in:%s', implode(',', array_keys($this->types))),
];
}
public function withValidator(Validator $validator): void
{
$validator->after(
function (Validator $validator): void {
if (!$validator->valid()) {
return;
}
$type = $this->convertString('type', 'all');
$this->attributes->add([
'type' => $type,
'types' => $this->mapAccountTypes($type),
]);
}
);
}
}

View File

@@ -23,77 +23,21 @@ declare(strict_types=1);
namespace FireflyIII\Api\V1\Requests\Models\Account;
use Carbon\Carbon;
use FireflyIII\Api\V1\Requests\AggregateFormRequest;
use FireflyIII\Api\V1\Requests\DateRangeRequest;
use FireflyIII\Api\V1\Requests\DateRequest;
use FireflyIII\Api\V1\Requests\PaginationRequest;
use FireflyIII\Models\Account;
use FireflyIII\Rules\IsValidSortInstruction;
use FireflyIII\Support\Facades\Preferences;
use FireflyIII\Support\Http\Api\AccountFilter;
use FireflyIII\Support\Request\ConvertsDataTypes;
use FireflyIII\User;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Validation\Validator;
class ShowRequest extends FormRequest
class ShowRequest extends AggregateFormRequest
{
use AccountFilter;
use ConvertsDataTypes;
public function getParameters(): array
protected function getRequests(): array
{
$limit = $this->convertInteger('limit');
if (0 === $limit) {
// get default for user:
/** @var User $user */
$user = auth()->user();
$limit = (int)Preferences::getForUser($user, 'listPageSize', 50)->data;
}
$page = $this->convertInteger('page');
$page = min(max(1, $page), 2 ** 16);
return [
'type' => $this->convertString('type', 'all'),
'limit' => $limit,
'sort' => $this->convertSortParameters('sort', Account::class),
'page' => $page,
[PaginationRequest::class, 'sort_class' => Account::class],
DateRangeRequest::class,
DateRequest::class,
AccountTypeApiRequest::class,
];
}
public function rules(): array
{
$keys = implode(',', array_keys($this->types));
return [
'date' => 'date',
'start' => 'date|present_with:end|before_or_equal:end|before:2038-01-17|after:1970-01-02',
'end' => 'date|present_with:start|after_or_equal:start|before:2038-01-17|after:1970-01-02',
'sort' => ['nullable', new IsValidSortInstruction(Account::class)],
'type' => sprintf('in:%s', $keys),
'limit' => 'numeric|min:1|max:131337',
'page' => 'numeric|min:1|max:131337',
];
}
public function withValidator(Validator $validator): void
{
$validator->after(
function (Validator $validator): void {
if (count($validator->failed()) > 0) {
return;
}
$data = $validator->getData();
if (array_key_exists('date', $data) && array_key_exists('start', $data) && array_key_exists('end', $data)) {
// assume valid dates, before we got here.
$start = Carbon::parse($data['start'], config('app.timezone'))->startOfDay();
$end = Carbon::parse($data['end'], config('app.timezone'))->endOfDay();
$date = Carbon::parse($data['date'], config('app.timezone'));
if (!$date->between($start, $end)) {
$validator->errors()->add('date', (string)trans('validation.between_date'));
}
}
}
);
}
}

View File

@@ -0,0 +1,84 @@
<?php
/*
* Copyright (c) 2025 https://github.com/ctrl-f5
*
* This file is part of Firefly III (https://github.com/firefly-iii).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
declare(strict_types=1);
namespace FireflyIII\Api\V1\Requests;
use FireflyIII\Rules\IsValidSortInstruction;
use FireflyIII\Support\Facades\Preferences;
use FireflyIII\User;
use Illuminate\Validation\Validator;
use RuntimeException;
class PaginationRequest extends ApiRequest
{
private ?string $sortClass = null;
public function handleConfig(array $config): void
{
parent::handleConfig($config);
$this->sortClass = $config['sort_class'] ?? null;
if (!$this->sortClass) {
throw new RuntimeException('PaginationRequest requires a sort_class config');
}
}
public function rules(): array
{
return [
'sort' => ['nullable', new IsValidSortInstruction($this->sortClass)],
'limit' => 'numeric|min:1|max:131337',
'page' => 'numeric|min:1|max:131337',
];
}
public function withValidator(Validator $validator): void
{
$validator->after(
function (Validator $validator): void {
if (!$validator->valid()) {
return;
}
$limit = $this->convertInteger('limit');
if (0 === $limit) {
// get default for user:
/** @var User $user */
$user = auth()->user();
$limit = (int)Preferences::getForUser($user, 'listPageSize', 50)->data;
}
$page = $this->convertInteger('page');
$page = min(max(1, $page), 2 ** 16);
$offset = ($page - 1) * $limit;
$sort = $this->sortClass ? $this->convertSortParameters('sort', $this->sortClass) : $this->get('sort');
$this->attributes->set('limit', $limit);
$this->attributes->set('sort', $sort);
$this->attributes->set('page', $page);
$this->attributes->set('offset', $offset);
}
);
}
}

View File

@@ -24,6 +24,7 @@ declare(strict_types=1);
namespace FireflyIII\Http\Controllers\Rule;
use Carbon\Carbon;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Http\Controllers\Controller;
use FireflyIII\Http\Requests\SelectTransactionsRequest;
@@ -56,7 +57,7 @@ class SelectController extends Controller
$this->middleware(
static function ($request, $next) {
app('view')->share('title', (string) trans('firefly.rules'));
app('view')->share('title', (string)trans('firefly.rules'));
app('view')->share('mainTitleIcon', 'fa-random');
return $next($request);
@@ -73,11 +74,20 @@ class SelectController extends Controller
/** @var User $user */
$user = auth()->user();
$accounts = implode(',', $request->get('accounts'));
// create new rule engine:
$newRuleEngine = app(RuleEngineInterface::class);
$newRuleEngine->setUser($user);
// add date operators.
if (null !== $request->get('start')) {
$startDate = new Carbon($request->get('start'));
$newRuleEngine->addOperator(['type' => 'date_after', 'value' => $startDate->format('Y-m-d')]);
}
if (null !== $request->get('end')) {
$endDate = new Carbon($request->get('end'));
$newRuleEngine->addOperator(['type' => 'date_before', 'value' => $endDate->format('Y-m-d')]);
}
// add extra operators:
$newRuleEngine->addOperator(['type' => 'account_id', 'value' => $accounts]);
@@ -102,7 +112,7 @@ class SelectController extends Controller
return redirect(route('rules.index'));
}
// does the user have shared accounts?
$subTitle = (string) trans('firefly.apply_rule_selection', ['title' => $rule->title]);
$subTitle = (string)trans('firefly.apply_rule_selection', ['title' => $rule->title]);
return view('rules.rule.select-transactions', compact('rule', 'subTitle'));
}
@@ -127,7 +137,7 @@ class SelectController extends Controller
// warn if nothing.
if (0 === count($textTriggers)) {
return response()->json(['html' => '', 'warning' => (string) trans('firefly.warning_no_valid_triggers')]);
return response()->json(['html' => '', 'warning' => (string)trans('firefly.warning_no_valid_triggers')]);
}
foreach ($textTriggers as $textTrigger) {
@@ -160,7 +170,7 @@ class SelectController extends Controller
// Warn the user if only a subset of transactions is returned
$warning = '';
if (0 === count($collection)) {
$warning = (string) trans('firefly.warning_no_matching_transactions');
$warning = (string)trans('firefly.warning_no_matching_transactions');
}
// Return json response
@@ -190,7 +200,7 @@ class SelectController extends Controller
$triggers = $rule->ruleTriggers;
if (0 === count($triggers)) {
return response()->json(['html' => '', 'warning' => (string) trans('firefly.warning_no_valid_triggers')]);
return response()->json(['html' => '', 'warning' => (string)trans('firefly.warning_no_valid_triggers')]);
}
// create new rule engine:
$newRuleEngine = app(RuleEngineInterface::class);
@@ -202,7 +212,7 @@ class SelectController extends Controller
$warning = '';
if (0 === count($collection)) {
$warning = (string) trans('firefly.warning_no_matching_transactions');
$warning = (string)trans('firefly.warning_no_matching_transactions');
}
// Return json response

View File

@@ -24,6 +24,7 @@ declare(strict_types=1);
namespace FireflyIII\Http\Controllers\RuleGroup;
use Carbon\Carbon;
use Exception;
use FireflyIII\Http\Controllers\Controller;
use FireflyIII\Http\Requests\SelectTransactionsRequest;
@@ -73,6 +74,16 @@ class ExecutionController extends Controller
$newRuleEngine = app(RuleEngineInterface::class);
$newRuleEngine->setUser($user);
// add date operators.
if (null !== $request->get('start')) {
$startDate = new Carbon($request->get('start'));
$newRuleEngine->addOperator(['type' => 'date_after', 'value' => $startDate->format('Y-m-d')]);
}
if (null !== $request->get('end')) {
$endDate = new Carbon($request->get('end'));
$newRuleEngine->addOperator(['type' => 'date_before', 'value' => $endDate->format('Y-m-d')]);
}
// add extra operators:
$newRuleEngine->addOperator(['type' => 'account_id', 'value' => $accounts]);

View File

@@ -34,11 +34,17 @@ abstract class AbstractTransformer extends TransformerAbstract
{
protected ParameterBag $parameters;
/**
* @deprecated
*/
final public function getParameters(): ParameterBag
{
return $this->parameters;
}
/**
* @deprecated
*/
final public function setParameters(ParameterBag $parameters): void
{
$this->parameters = $parameters;

View File

@@ -30,7 +30,6 @@ use FireflyIII\Models\Account;
use FireflyIII\Models\TransactionCurrency;
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
use FireflyIII\Support\Facades\Amount;
use Symfony\Component\HttpFoundation\ParameterBag;
/**
* Class AccountTransformer
@@ -46,7 +45,6 @@ class AccountTransformer extends AbstractTransformer
*/
public function __construct()
{
$this->parameters = new ParameterBag();
$this->repository = app(AccountRepositoryInterface::class);
$this->convertToPrimary = Amount::convertToPrimary();
$this->primary = Amount::getPrimaryCurrency();

8
composer.lock generated
View File

@@ -11333,11 +11333,11 @@
},
{
"name": "phpstan/phpstan",
"version": "2.1.30",
"version": "2.1.31",
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/phpstan/phpstan/zipball/a4a7f159927983dd4f7c8020ed227d80b7f39d7d",
"reference": "a4a7f159927983dd4f7c8020ed227d80b7f39d7d",
"url": "https://api.github.com/repos/phpstan/phpstan/zipball/ead89849d879fe203ce9292c6ef5e7e76f867b96",
"reference": "ead89849d879fe203ce9292c6ef5e7e76f867b96",
"shasum": ""
},
"require": {
@@ -11382,7 +11382,7 @@
"type": "github"
}
],
"time": "2025-10-02T16:07:52+00:00"
"time": "2025-10-10T14:14:11+00:00"
},
{
"name": "phpstan/phpstan-deprecation-rules",

View File

@@ -79,7 +79,7 @@ return [
// see cer.php for exchange rates feature flag.
],
'version' => 'develop/2025-10-10',
'build_time' => 1760095871,
'build_time' => 1760115185,
'api_version' => '2.1.0', // field is no longer used.
'db_version' => 28, // field is no longer used.

12
package-lock.json generated
View File

@@ -4075,9 +4075,9 @@
"license": "MIT"
},
"node_modules/baseline-browser-mapping": {
"version": "2.8.15",
"resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.8.15.tgz",
"integrity": "sha512-qsJ8/X+UypqxHXN75M7dF88jNK37dLBRW7LeUzCPz+TNs37G8cfWy9nWzS+LS//g600zrt2le9KuXt0rWfDz5Q==",
"version": "2.8.16",
"resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.8.16.tgz",
"integrity": "sha512-OMu3BGQ4E7P1ErFsIPpbJh0qvDudM/UuJeHgkAvfWe+0HFJCXh+t/l8L6fVLR55RI/UbKrVLnAXZSVwd9ysWYw==",
"dev": true,
"license": "Apache-2.0",
"bin": {
@@ -7088,9 +7088,9 @@
}
},
"node_modules/i18next": {
"version": "25.5.3",
"resolved": "https://registry.npmjs.org/i18next/-/i18next-25.5.3.tgz",
"integrity": "sha512-joFqorDeQ6YpIXni944upwnuHBf5IoPMuqAchGVeQLdWC2JOjxgM9V8UGLhNIIH/Q8QleRxIi0BSRQehSrDLcg==",
"version": "25.6.0",
"resolved": "https://registry.npmjs.org/i18next/-/i18next-25.6.0.tgz",
"integrity": "sha512-tTn8fLrwBYtnclpL5aPXK/tAYBLWVvoHM1zdfXoRNLcI+RvtMsoZRV98ePlaW3khHYKuNh/Q65W/+NVFUeIwVw==",
"funding": [
{
"type": "individual",

View File

@@ -24,6 +24,8 @@
</p>
<div class="row">
<div class="col-lg-6 col-md-8 col-sm-12 col-xs-12">
{{ ExpandedForm.date('start') }}
{{ ExpandedForm.date('end') }}
{{ AccountForm.assetAccountCheckList('accounts', {'select_all': true,'class': 'account-checkbox', 'label': trans('firefly.include_transactions_from_accounts') }) }}
</div>
</div>

View File

@@ -23,6 +23,8 @@
</p>
<div class="row">
<div class="col-lg-6 col-md-8 col-sm-12 col-xs-12">
{{ ExpandedForm.date('start') }}
{{ ExpandedForm.date('end') }}
{{ AccountForm.assetAccountCheckList('accounts', {'select_all': true, 'class': 'account-checkbox', 'label': trans('firefly.include_transactions_from_accounts') }) }}
</div>
</div>