| 
									
										
										
										
											2024-03-06 17:50:16 -05:00
										 |  |  | <?php | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /** | 
					
						
							| 
									
										
										
										
											2024-03-07 13:00:57 -05:00
										 |  |  |  * ActionExpression.php | 
					
						
							| 
									
										
										
										
											2024-03-06 17:50:16 -05:00
										 |  |  |  * Copyright (c) 2024 Michael Thomas | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * 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\TransactionRules\Expressions; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | use Symfony\Component\ExpressionLanguage\ExpressionLanguage; | 
					
						
							|  |  |  | use Symfony\Component\ExpressionLanguage\SyntaxError; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-03-07 13:00:57 -05:00
										 |  |  | class ActionExpression | 
					
						
							| 
									
										
										
										
											2024-03-06 17:50:16 -05:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2025-05-04 17:41:26 +02:00
										 |  |  |     private static array                $NAMES | 
					
						
							| 
									
										
										
										
											2024-03-16 23:06:16 +01:00
										 |  |  |         = [ | 
					
						
							|  |  |  |             //        'transaction_group_id',
 | 
					
						
							|  |  |  |             //        'user_id',
 | 
					
						
							|  |  |  |             //        'user_group_id',
 | 
					
						
							|  |  |  |             'created_at', | 
					
						
							|  |  |  |             'updated_at', | 
					
						
							|  |  |  |             'transaction_group_title', | 
					
						
							|  |  |  |             'group_created_at', | 
					
						
							|  |  |  |             'group_updated_at', | 
					
						
							|  |  |  |             //        'transaction_journal_id',
 | 
					
						
							|  |  |  |             //        'transaction_type_id',
 | 
					
						
							|  |  |  |             'description', | 
					
						
							|  |  |  |             'date', | 
					
						
							|  |  |  |             //        'order',
 | 
					
						
							|  |  |  |             'transaction_type_type', | 
					
						
							|  |  |  |             //        'source_transaction_id',
 | 
					
						
							|  |  |  |             'source_account_id', | 
					
						
							|  |  |  |             //        'reconciled',
 | 
					
						
							|  |  |  |             'amount', | 
					
						
							|  |  |  |             //        'currency_id',
 | 
					
						
							|  |  |  |             'currency_code', | 
					
						
							|  |  |  |             'currency_name', | 
					
						
							|  |  |  |             'currency_symbol', | 
					
						
							|  |  |  |             'currency_decimal_places', | 
					
						
							|  |  |  |             'foreign_amount', | 
					
						
							|  |  |  |             //        'foreign_currency_id',
 | 
					
						
							|  |  |  |             'foreign_currency_code', | 
					
						
							|  |  |  |             'foreign_currency_name', | 
					
						
							|  |  |  |             'foreign_currency_symbol', | 
					
						
							|  |  |  |             'foreign_currency_decimal_places', | 
					
						
							|  |  |  |             'destination_account_id', | 
					
						
							|  |  |  |             'source_account_name', | 
					
						
							|  |  |  |             'source_account_iban', | 
					
						
							|  |  |  |             'source_account_type', | 
					
						
							|  |  |  |             'destination_account_name', | 
					
						
							|  |  |  |             'destination_account_iban', | 
					
						
							|  |  |  |             'destination_account_type', | 
					
						
							|  |  |  |             'category_id', | 
					
						
							|  |  |  |             'category_name', | 
					
						
							|  |  |  |             'budget_id', | 
					
						
							|  |  |  |             'budget_name', | 
					
						
							|  |  |  |             'tags', | 
					
						
							|  |  |  |             //        'attachments',
 | 
					
						
							|  |  |  |             'interest_date', | 
					
						
							|  |  |  |             'payment_date', | 
					
						
							|  |  |  |             'invoice_date', | 
					
						
							|  |  |  |             'book_date', | 
					
						
							|  |  |  |             'due_date', | 
					
						
							|  |  |  |             'process_date', | 
					
						
							|  |  |  |             //        'destination_transaction_id',
 | 
					
						
							|  |  |  |             'notes', | 
					
						
							|  |  |  |         ]; | 
					
						
							| 
									
										
										
										
											2025-05-04 13:04:33 +02:00
										 |  |  |     private readonly ExpressionLanguage $expressionLanguage; | 
					
						
							|  |  |  |     private readonly bool               $isExpression; | 
					
						
							|  |  |  |     private readonly ?SyntaxError       $validationError; | 
					
						
							| 
									
										
										
										
											2024-03-06 17:50:16 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-05-04 13:04:33 +02:00
										 |  |  |     public function __construct(private readonly string $expr) | 
					
						
							| 
									
										
										
										
											2024-03-06 17:50:16 -05:00
										 |  |  |     { | 
					
						
							| 
									
										
										
										
											2024-03-07 13:00:57 -05:00
										 |  |  |         $this->expressionLanguage = app(ExpressionLanguage::class); | 
					
						
							| 
									
										
										
										
											2024-03-06 17:50:16 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-05-04 13:04:33 +02:00
										 |  |  |         $this->isExpression       = self::isExpression($this->expr); | 
					
						
							| 
									
										
										
										
											2024-03-10 06:17:31 +01:00
										 |  |  |         $this->validationError    = $this->validate(); | 
					
						
							| 
									
										
										
										
											2024-03-06 17:50:16 -05:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     private static function isExpression(string $expr): bool | 
					
						
							|  |  |  |     { | 
					
						
							| 
									
										
										
										
											2024-03-10 08:08:26 +01:00
										 |  |  |         return str_starts_with($expr, '=') && strlen($expr) > 1; | 
					
						
							| 
									
										
										
										
											2024-03-06 17:50:16 -05:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-03-07 12:23:32 -05:00
										 |  |  |     private function validate(): ?SyntaxError | 
					
						
							| 
									
										
										
										
											2024-03-06 17:50:16 -05:00
										 |  |  |     { | 
					
						
							|  |  |  |         if (!$this->isExpression) { | 
					
						
							| 
									
										
										
										
											2024-03-07 12:23:32 -05:00
										 |  |  |             return null; | 
					
						
							| 
									
										
										
										
											2024-03-06 17:50:16 -05:00
										 |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         try { | 
					
						
							| 
									
										
										
										
											2024-03-07 12:23:32 -05:00
										 |  |  |             $this->lint(); | 
					
						
							| 
									
										
										
										
											2024-03-10 06:17:31 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-03-07 12:23:32 -05:00
										 |  |  |             return null; | 
					
						
							| 
									
										
										
										
											2024-03-06 17:50:16 -05:00
										 |  |  |         } catch (SyntaxError $e) { | 
					
						
							| 
									
										
										
										
											2024-03-07 12:23:32 -05:00
										 |  |  |             return $e; | 
					
						
							| 
									
										
										
										
											2024-03-06 17:50:16 -05:00
										 |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-03-07 12:23:32 -05:00
										 |  |  |     private function lint(): void | 
					
						
							| 
									
										
										
										
											2024-03-06 17:50:16 -05:00
										 |  |  |     { | 
					
						
							|  |  |  |         if (!$this->isExpression) { | 
					
						
							|  |  |  |             return; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         $this->lintExpression(substr($this->expr, 1)); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-03-16 23:06:16 +01:00
										 |  |  |     private function lintExpression(string $expr): void | 
					
						
							| 
									
										
										
										
											2024-03-07 12:23:32 -05:00
										 |  |  |     { | 
					
						
							| 
									
										
										
										
											2024-03-16 23:06:16 +01:00
										 |  |  |         $this->expressionLanguage->lint($expr, self::$NAMES); | 
					
						
							| 
									
										
										
										
											2024-03-07 12:23:32 -05:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-03-09 13:02:04 -05:00
										 |  |  |     public function getValidationError(): ?SyntaxError | 
					
						
							| 
									
										
										
										
											2024-03-07 12:23:32 -05:00
										 |  |  |     { | 
					
						
							|  |  |  |         return $this->validationError; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-03-16 23:06:16 +01:00
										 |  |  |     public function isValid(): bool | 
					
						
							|  |  |  |     { | 
					
						
							| 
									
										
										
										
											2025-05-27 17:06:15 +02:00
										 |  |  |         return !$this->validationError instanceof SyntaxError; | 
					
						
							| 
									
										
										
										
											2024-03-16 23:06:16 +01:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-03-06 17:50:16 -05:00
										 |  |  |     private function evaluateExpression(string $expr, array $journal): string | 
					
						
							|  |  |  |     { | 
					
						
							| 
									
										
										
										
											2024-03-07 20:58:43 -05:00
										 |  |  |         $result = $this->expressionLanguage->evaluate($expr, $journal); | 
					
						
							| 
									
										
										
										
											2024-03-10 06:17:31 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-12-22 08:43:12 +01:00
										 |  |  |         return (string) $result; | 
					
						
							| 
									
										
										
										
											2024-03-06 17:50:16 -05:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     public function evaluate(array $journal): string | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         if (!$this->isExpression) { | 
					
						
							|  |  |  |             return $this->expr; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         return $this->evaluateExpression(substr($this->expr, 1), $journal); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } |