2019-11-12 22:28:17 +01:00
|
|
|
<?php
|
|
|
|
/**
|
2020-09-06 11:38:10 +02:00
|
|
|
* Invoice Ninja (https://invoiceninja.com).
|
2019-11-12 22:28:17 +01:00
|
|
|
*
|
|
|
|
* @link https://github.com/invoiceninja/invoiceninja source repository
|
|
|
|
*
|
2020-01-07 01:13:47 +01:00
|
|
|
* @copyright Copyright (c) 2020. Invoice Ninja LLC (https://invoiceninja.com)
|
2019-11-12 22:28:17 +01:00
|
|
|
*
|
|
|
|
* @license https://opensource.org/licenses/AAL
|
|
|
|
*/
|
|
|
|
|
|
|
|
namespace App\Utils\Traits;
|
|
|
|
|
|
|
|
use App\DataMapper\CompanySettings;
|
2020-04-21 07:16:45 +02:00
|
|
|
use App\Models\Company;
|
|
|
|
use App\Utils\Ninja;
|
2020-10-28 11:10:49 +01:00
|
|
|
use stdClass;
|
2019-11-12 22:28:17 +01:00
|
|
|
|
|
|
|
/**
|
2020-09-06 11:38:10 +02:00
|
|
|
* Class CompanySettingsSaver.
|
2020-04-21 07:16:45 +02:00
|
|
|
*
|
|
|
|
* Whilst it may appear that this CompanySettingsSaver and ClientGroupSettingsSaver
|
|
|
|
* could be duplicates, they are not.
|
|
|
|
*
|
2020-09-06 11:38:10 +02:00
|
|
|
* Each requires their own approach to saving and attempts to
|
2020-04-21 07:16:45 +02:00
|
|
|
* merge the two code paths should be avoided.
|
2019-11-12 22:28:17 +01:00
|
|
|
*/
|
|
|
|
trait CompanySettingsSaver
|
|
|
|
{
|
2019-12-30 22:59:12 +01:00
|
|
|
/**
|
2020-09-06 11:38:10 +02:00
|
|
|
* Saves a setting object.
|
2019-12-30 22:59:12 +01:00
|
|
|
*
|
|
|
|
* 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)
|
|
|
|
{
|
2020-03-21 06:37:30 +01:00
|
|
|
/* No Settings, No Save!*/
|
2020-09-06 11:38:10 +02:00
|
|
|
if (! $settings) {
|
2019-12-30 22:59:12 +01:00
|
|
|
return;
|
2020-03-21 06:37:30 +01:00
|
|
|
}
|
2020-09-06 11:38:10 +02:00
|
|
|
|
2020-03-06 12:10:59 +01:00
|
|
|
//Unset Protected Properties.
|
2020-03-21 06:37:30 +01:00
|
|
|
foreach (CompanySettings::$protected_fields as $field) {
|
2019-12-30 22:59:12 +01:00
|
|
|
unset($settings[$field]);
|
2020-03-21 06:37:30 +01:00
|
|
|
}
|
2019-12-30 22:59:12 +01:00
|
|
|
|
|
|
|
$settings = $this->checkSettingType($settings);
|
|
|
|
|
|
|
|
$company_settings = CompanySettings::defaults();
|
2020-04-21 07:16:45 +02:00
|
|
|
|
2020-09-06 11:38:10 +02:00
|
|
|
foreach ($settings as $key => $value) {
|
2019-12-30 22:59:12 +01:00
|
|
|
if (is_null($settings->{$key})) {
|
|
|
|
$company_settings->{$key} = '';
|
|
|
|
} else {
|
2020-09-06 11:38:10 +02:00
|
|
|
$company_settings->{$key} = $value;
|
2019-12-30 22:59:12 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
$entity->settings = $company_settings;
|
2020-03-06 12:10:59 +01:00
|
|
|
|
2019-12-30 22:59:12 +01:00
|
|
|
$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)
|
|
|
|
{
|
2020-09-06 11:38:10 +02:00
|
|
|
$settings = (object) $settings;
|
2020-03-06 12:10:59 +01:00
|
|
|
|
2019-12-30 22:59:12 +01:00
|
|
|
$casts = CompanySettings::$casts;
|
2020-09-06 11:38:10 +02:00
|
|
|
|
2019-12-30 22:59:12 +01:00
|
|
|
ksort($casts);
|
|
|
|
|
|
|
|
foreach ($casts as $key => $value) {
|
2020-04-21 07:16:45 +02:00
|
|
|
if (in_array($key, CompanySettings::$string_casts)) {
|
2020-09-06 11:38:10 +02:00
|
|
|
$value = 'string';
|
2020-03-06 23:48:03 +01:00
|
|
|
|
2020-09-06 11:38:10 +02:00
|
|
|
if (! property_exists($settings, $key)) {
|
2020-03-06 23:48:03 +01:00
|
|
|
continue;
|
2020-09-06 11:38:10 +02:00
|
|
|
} elseif (! $this->checkAttribute($value, $settings->{$key})) {
|
2020-03-06 23:48:03 +01:00
|
|
|
return [$key, $value, $settings->{$key}];
|
|
|
|
}
|
|
|
|
|
|
|
|
continue;
|
|
|
|
}
|
2019-12-30 22:59:12 +01:00
|
|
|
/*Separate loop if it is a _id field which is an integer cast as a string*/
|
2020-03-06 23:48:03 +01:00
|
|
|
elseif (substr($key, -3) == '_id' || substr($key, -14) == 'number_counter') {
|
2020-09-06 11:38:10 +02:00
|
|
|
$value = 'integer';
|
|
|
|
|
|
|
|
if (! property_exists($settings, $key)) {
|
2019-12-30 22:59:12 +01:00
|
|
|
continue;
|
2020-09-06 11:38:10 +02:00
|
|
|
} elseif (! $this->checkAttribute($value, $settings->{$key})) {
|
2020-03-06 12:10:59 +01:00
|
|
|
return [$key, $value, $settings->{$key}];
|
2019-12-30 22:59:12 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
continue;
|
2020-03-21 06:37:30 +01:00
|
|
|
} elseif ($key == 'pdf_variables') {
|
2020-03-10 12:32:45 +01:00
|
|
|
continue;
|
|
|
|
}
|
2019-12-30 22:59:12 +01:00
|
|
|
|
|
|
|
/* Handles unset settings or blank strings */
|
2020-09-06 11:38:10 +02:00
|
|
|
if (! property_exists($settings, $key) || is_null($settings->{$key}) || ! isset($settings->{$key}) || $settings->{$key} == '') {
|
2019-12-30 22:59:12 +01:00
|
|
|
continue;
|
2020-03-21 06:37:30 +01:00
|
|
|
}
|
2019-12-30 22:59:12 +01:00
|
|
|
|
|
|
|
/*Catch all filter */
|
2020-09-06 11:38:10 +02:00
|
|
|
if (! $this->checkAttribute($value, $settings->{$key})) {
|
2020-03-06 12:10:59 +01:00
|
|
|
return [$key, $value, $settings->{$key}];
|
2020-03-21 06:37:30 +01:00
|
|
|
}
|
2019-12-30 22:59:12 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
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 object stdClass object
|
|
|
|
*/
|
2020-10-28 11:10:49 +01:00
|
|
|
private function checkSettingType($settings) : stdClass
|
2019-12-30 22:59:12 +01:00
|
|
|
{
|
2020-09-06 11:38:10 +02:00
|
|
|
$settings = (object) $settings;
|
2020-03-06 12:10:59 +01:00
|
|
|
|
2019-12-30 22:59:12 +01:00
|
|
|
$casts = CompanySettings::$casts;
|
2020-09-06 11:38:10 +02:00
|
|
|
|
2019-12-30 22:59:12 +01:00
|
|
|
foreach ($casts as $key => $value) {
|
2020-04-21 07:16:45 +02:00
|
|
|
if (in_array($key, CompanySettings::$string_casts)) {
|
2020-09-06 11:38:10 +02:00
|
|
|
$value = 'string';
|
|
|
|
|
|
|
|
if (! property_exists($settings, $key)) {
|
2020-03-06 12:10:59 +01:00
|
|
|
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});
|
|
|
|
}
|
|
|
|
|
2020-03-21 06:37:30 +01:00
|
|
|
continue;
|
2020-03-06 12:10:59 +01:00
|
|
|
}
|
2019-12-30 22:59:12 +01:00
|
|
|
/*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') {
|
2020-09-06 11:38:10 +02:00
|
|
|
$value = 'integer';
|
|
|
|
|
|
|
|
if (! property_exists($settings, $key)) {
|
2019-12-30 22:59:12 +01:00
|
|
|
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;
|
2020-03-21 06:37:30 +01:00
|
|
|
} elseif ($key == 'pdf_variables') {
|
2020-03-10 12:32:45 +01:00
|
|
|
settype($settings->{$key}, 'object');
|
|
|
|
}
|
2019-12-30 22:59:12 +01:00
|
|
|
|
|
|
|
/* Handles unset settings or blank strings */
|
2020-09-06 11:38:10 +02:00
|
|
|
if (! property_exists($settings, $key) || is_null($settings->{$key}) || ! isset($settings->{$key}) || $settings->{$key} == '') {
|
2019-12-30 22:59:12 +01:00
|
|
|
continue;
|
2020-03-21 06:37:30 +01:00
|
|
|
}
|
2019-12-30 22:59:12 +01:00
|
|
|
|
|
|
|
/*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});
|
|
|
|
}
|
|
|
|
}
|
2020-03-06 12:10:59 +01:00
|
|
|
|
2019-12-30 22:59:12 +01:00
|
|
|
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':
|
2020-03-11 12:05:05 +01:00
|
|
|
return ctype_digit(strval(abs($value)));
|
2019-12-30 22:59:12 +01:00
|
|
|
case 'real':
|
|
|
|
case 'float':
|
|
|
|
case 'double':
|
|
|
|
return is_float($value) || is_numeric(strval($value));
|
|
|
|
case 'string':
|
|
|
|
return 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($string);
|
2020-09-06 11:38:10 +02:00
|
|
|
|
|
|
|
return json_last_error() == JSON_ERROR_NONE;
|
2019-12-30 22:59:12 +01:00
|
|
|
default:
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
2020-04-21 07:16:45 +02:00
|
|
|
|
|
|
|
private function getAccountFromEntity($entity)
|
|
|
|
{
|
2020-09-06 11:38:10 +02:00
|
|
|
if ($entity instanceof Company) {
|
2020-04-21 07:16:45 +02:00
|
|
|
return $entity->account;
|
2020-09-06 11:38:10 +02:00
|
|
|
}
|
2020-04-21 07:16:45 +02:00
|
|
|
|
|
|
|
return $entity->company->account;
|
|
|
|
}
|
2019-12-30 22:59:12 +01:00
|
|
|
}
|