1
0
mirror of https://github.com/invoiceninja/invoiceninja.git synced 2024-11-13 22:54:25 +01:00
invoiceninja/app/Utils/Traits/CompanySettingsSaver.php

279 lines
8.9 KiB
PHP
Raw Normal View History

<?php
/**
* Invoice Ninja (https://invoiceninja.com).
*
* @link https://github.com/invoiceninja/invoiceninja source repository
*
2023-01-28 23:21:40 +01:00
* @copyright Copyright (c) 2023. Invoice Ninja LLC (https://invoiceninja.com)
*
2021-06-16 08:58:16 +02:00
* @license https://www.elastic.co/licensing/elastic-license
*/
namespace App\Utils\Traits;
use App\DataMapper\CompanySettings;
use App\Models\Company;
2020-10-28 11:10:49 +01:00
use stdClass;
/**
* Class CompanySettingsSaver.
*
* Whilst it may appear that this CompanySettingsSaver and ClientGroupSettingsSaver
* could be duplicates, they are not.
*
* Each requires their own approach to saving and attempts to
* merge the two code paths should be avoided.
*/
trait CompanySettingsSaver
{
/**
* Saves a setting object.
*
* Works for groups|clients|companies
* @param array $settings The request input settings array
* @param object $entity The entity which the settings belongs to
* @return void
*/
public function saveSettings($settings, $entity)
{
/* No Settings, No Save!*/
if (! $settings) {
return;
}
//Unset Protected Properties.
foreach (CompanySettings::$protected_fields as $field) {
unset($settings[$field]);
}
$settings = $this->checkSettingType($settings);
$company_settings = CompanySettings::defaults();
foreach ($settings as $key => $value) {
if (is_null($settings->{$key})) {
$company_settings->{$key} = '';
} else {
$company_settings->{$key} = $value;
}
}
if (property_exists($settings, 'translations')) {
//this pass will handle any null values that are in the translations
2021-07-22 10:33:25 +02:00
foreach ($settings->translations as $key => $value) {
if (is_array($settings->translations)) {
2022-04-21 08:04:59 +02:00
if (is_null($settings->translations[$key])) {
$settings->translations[$key] = '';
}
} elseif (is_object($settings->translations)) {
2022-04-21 08:04:59 +02:00
if (is_null($settings->translations->{$key})) {
$settings->translations->{$key} = '';
}
2021-07-22 10:33:25 +02:00
}
2020-12-16 12:52:40 +01:00
}
2020-12-14 21:53:31 +01:00
2021-07-22 10:33:25 +02:00
$company_settings->translations = $settings->translations;
}
2020-12-14 21:53:31 +01:00
$entity->settings = $company_settings;
$entity->save();
}
/**
* Used for custom validation of inbound
* settings request.
*
* Returns an array of errors, or boolean TRUE
* on successful validation
* @param array $settings The request() settings array
* @return array|bool Array on failure, boolean TRUE on success
*/
public function validateSettings($settings)
{
$settings = (object) $settings;
$casts = CompanySettings::$casts;
ksort($casts);
foreach ($casts as $key => $value) {
if (in_array($key, CompanySettings::$string_casts)) {
$value = 'string';
if (! property_exists($settings, $key)) {
continue;
} elseif (! $this->checkAttribute($value, $settings->{$key})) {
return [$key, $value, $settings->{$key}];
}
continue;
}
/*Separate loop if it is a _id field which is an integer cast as a string*/
elseif (substr($key, -3) == '_id' || substr($key, -14) == 'number_counter') {
$value = 'integer';
2023-02-16 02:36:09 +01:00
if ($key == 'besr_id') {
2022-06-30 09:51:39 +02:00
$value = 'string';
2023-02-16 02:36:09 +01:00
}
2022-06-30 09:51:39 +02:00
if (! property_exists($settings, $key)) {
continue;
} elseif (! $this->checkAttribute($value, $settings->{$key})) {
return [$key, $value, $settings->{$key}];
}
continue;
} elseif ($key == 'pdf_variables') {
continue;
}
/* Handles unset settings or blank strings */
if (! property_exists($settings, $key) || is_null($settings->{$key}) || ! isset($settings->{$key}) || $settings->{$key} == '') {
continue;
}
/*Catch all filter */
if (! $this->checkAttribute($value, $settings->{$key})) {
return [$key, $value, $settings->{$key}];
}
}
return true;
}
/**
* Checks the settings object for
* correct property types.
*
* The method will drop invalid types from
* the object and will also settype() the property
* so that it can be saved cleanly
*
* @param array $settings The settings request() array
* @return stdClass stdClass object
*/
2020-10-28 11:10:49 +01:00
private function checkSettingType($settings) : stdClass
{
$settings = (object) $settings;
$casts = CompanySettings::$casts;
foreach ($casts as $key => $value) {
if (in_array($key, CompanySettings::$string_casts)) {
$value = 'string';
if (! property_exists($settings, $key)) {
continue;
} elseif ($this->checkAttribute($value, $settings->{$key})) {
if (substr($key, -3) == '_id') {
settype($settings->{$key}, 'string');
} else {
settype($settings->{$key}, $value);
}
} else {
unset($settings->{$key});
}
continue;
}
/*Separate loop if it is a _id field which is an integer cast as a string*/
if (substr($key, -3) == '_id' || substr($key, -14) == 'number_counter') {
$value = 'integer';
if ($key == 'gmail_sending_user_id') {
2021-02-22 11:35:00 +01:00
$value = 'string';
}
2021-02-22 11:35:00 +01:00
2023-02-16 02:36:09 +01:00
if ($key == 'besr_id') {
2022-06-30 09:51:39 +02:00
$value = 'string';
2023-02-16 02:36:09 +01:00
}
2022-06-30 09:51:39 +02:00
if (! property_exists($settings, $key)) {
continue;
} elseif ($this->checkAttribute($value, $settings->{$key})) {
if (substr($key, -3) == '_id') {
settype($settings->{$key}, 'string');
} else {
settype($settings->{$key}, $value);
}
} else {
unset($settings->{$key});
}
continue;
} elseif ($key == 'pdf_variables') {
settype($settings->{$key}, 'object');
}
//try casting floats here
if ($value == 'float' && property_exists($settings, $key)) {
$settings->{$key} = floatval($settings->{$key});
}
/* Handles unset settings or blank strings */
if (! property_exists($settings, $key) || is_null($settings->{$key}) || ! isset($settings->{$key}) || $settings->{$key} == '') {
continue;
}
/*Catch all filter */
if ($this->checkAttribute($value, $settings->{$key})) {
if ($value == 'string' && is_null($settings->{$key})) {
$settings->{$key} = '';
}
settype($settings->{$key}, $value);
} else {
unset($settings->{$key});
}
}
return $settings;
}
/**
* Type checks a object property.
* @param string $key The type
* @param string $value The object property
* @return bool TRUE if the property is the expected type
*/
private function checkAttribute($key, $value) :bool
{
switch ($key) {
case 'int':
case 'integer':
return ctype_digit(strval(abs((int) $value)));
2021-02-23 11:04:39 +01:00
// return is_int($value) || ctype_digit(strval(abs($value)));
case 'real':
case 'float':
case 'double':
return ! is_string($value) && (is_float($value) || is_numeric(strval($value)));
2022-03-23 07:37:39 +01:00
// return is_float($value) || is_numeric(strval($value));
case 'string':
2021-04-06 02:43:56 +02:00
return (is_string($value) && method_exists($value, '__toString')) || is_null($value) || is_string($value);
case 'bool':
case 'boolean':
return is_bool($value) || (int) filter_var($value, FILTER_VALIDATE_BOOLEAN);
case 'object':
return is_object($value);
case 'array':
return is_array($value);
case 'json':
json_decode($value);
2023-02-16 02:36:09 +01:00
return json_last_error() == JSON_ERROR_NONE;
default:
return false;
}
}
private function getAccountFromEntity($entity)
{
if ($entity instanceof Company) {
return $entity->account;
}
return $entity->company->account;
}
}