|
| 1 | +<?php |
| 2 | + |
| 3 | +namespace RESTAPI\Fields; |
| 4 | + |
| 5 | +require_once 'RESTAPI/autoloader.inc'; |
| 6 | + |
| 7 | +use RESTAPI; |
| 8 | +use RESTAPI\Core\Field; |
| 9 | + |
| 10 | +/** |
| 11 | + * Defines a Field object for validating and storing key length values in the pfSense configuration. This is namely |
| 12 | + * for IPsec Phase 2 entries to handle the 'auto' keyword as an integer. |
| 13 | + */ |
| 14 | +class KeyLenField extends Field { |
| 15 | + /** |
| 16 | + * Defines the KeyLenField object and sets its options. |
| 17 | + * @param bool $required If `true`, this field is required to have a value at all times. |
| 18 | + * @param bool $unique If `true`, this field must be unique from all other parent model objects. Enabling this |
| 19 | + * option requires the Model $context to be set AND the Model $context must have a `config_path` set. |
| 20 | + * @param mixed|null $default Assign a default string value to assign this Field if no value is present. |
| 21 | + * @param string $default_callable Defines a callable method that should be called to populate the default value |
| 22 | + * for this field. It is strongly encouraged to use a default callable when the default is variable and may change |
| 23 | + * dynamically. |
| 24 | + * @param array $choices An array of value choices this Field can be assigned. This can either be an indexed array |
| 25 | + * of the exact choice values, or an associative array where the array key is the exact choice value and the array |
| 26 | + * value is a verbose name for the choice. Verbose choice name are used by ModelForms when generating web pages |
| 27 | + * for a given Model. |
| 28 | + * @param string $choices_callable Assign a callable method from this Field object OR the parent Model context to |
| 29 | + * execute to populate choices for this field. This callable must be a method assigned on this Field object OR the |
| 30 | + * parent Model object that returns an array of valid choices in the same format as $choices. This is helpful when |
| 31 | + * choices are dynamic and must be populate at runtime instead of pre-determined sets of values. |
| 32 | + * @param bool $allow_null If `true`, null values will be allowed by this field. |
| 33 | + * @param bool $editable Set to `false` to prevent this field's value from being changed after its initial creation. |
| 34 | + * @param bool $read_only If `true`, this field can only read its value and cannot write its value to config. |
| 35 | + * @param bool $write_only Set to `true` to make this field write-only. This will prevent the field's current value |
| 36 | + * from being displayed in the representation data. This is ideal for potentially sensitive Fields like passwords, |
| 37 | + * keys, and hashes. |
| 38 | + * @param bool $representation_only Set to `true` to make this field only present in its representation form. This |
| 39 | + * effectively prevents the Field from being converted to an internal value which is saved to the pfSense config. |
| 40 | + * This should only be used for Fields that do not relate directly to a configuration value. |
| 41 | + * @param bool $many If `true`, the value must be an array of many strings. |
| 42 | + * @param int $many_minimum When $many is set to `true`, this sets the minimum number of array entries required. |
| 43 | + * @param int $many_maximum When $many is set to `true`, this sets the maximum number of array entries allowed. |
| 44 | + * @param int $minimum The minimum value this value can be. |
| 45 | + * @param int $maximum The maximum value this value can be. |
| 46 | + * @param string|null $delimiter Assigns the string delimiter to use when writing array values to config. |
| 47 | + * Use `null` if this field is stored as an actual array in config. This is only available if $many is set to |
| 48 | + * `true`. Defaults to `,` to store as comma-separated string. |
| 49 | + * @param string $verbose_name The detailed name for this Field. This name will be used in non-programmatic areas |
| 50 | + * like web pages and help text. This Field will default to property name assigned to the parent Model with |
| 51 | + * underscores converted to spaces. |
| 52 | + * @param string $verbose_name_plural The plural form of $verbose_name. This defaults to $verbose_name with `s` |
| 53 | + * suffixed or `es` suffixes to strings already ending with `s`. |
| 54 | + * @param string $internal_name Assign a different field name to use when referring to the internal field as it's |
| 55 | + * stored in the pfSense configuration. |
| 56 | + * @param string $internal_namespace Sets the namespace this field belongs to internally. This can be used to nest |
| 57 | + * the Fields internal value under a specific namespace as an associative array. This only applies to the internal |
| 58 | + * value, not the representation value. |
| 59 | + * @param array $referenced_by An array that specifies other Models and Field's that reference this Field's parent |
| 60 | + * Model using this Field's value. This will prevent the parent Model object from being deleted while it is actively |
| 61 | + * referenced by another Model object. The array key must be the name of the Model class that references this Field, |
| 62 | + * and the value must be a Field within that Model. The framework will automatically search for any existing Model |
| 63 | + * objects that have the referenced Field assigned a value that matches this Field's value. |
| 64 | + * @param array $conditions An array of conditions the field must meet to be included. This allows you to specify |
| 65 | + * conditions of other Fields within the parent Model context. For example, if the parent Model context has two |
| 66 | + * Fields, one field named `type` and the other being this field; and you only want this field to be included if |
| 67 | + * `type` is equal to `type1`, you could assign ["type" => "type1"] to this parameter. |
| 68 | + * @param array $validators An array of Validator objects to run against this field. |
| 69 | + * @param string $help_text Set a description for this field. This description will be used in API documentation. |
| 70 | + */ |
| 71 | + public function __construct( |
| 72 | + bool $required = false, |
| 73 | + bool $unique = false, |
| 74 | + mixed $default = null, |
| 75 | + string $default_callable = '', |
| 76 | + array $choices = [], |
| 77 | + string $choices_callable = '', |
| 78 | + bool $allow_null = false, |
| 79 | + bool $editable = true, |
| 80 | + bool $read_only = false, |
| 81 | + bool $write_only = false, |
| 82 | + bool $representation_only = false, |
| 83 | + bool $many = false, |
| 84 | + int $many_minimum = 0, |
| 85 | + int $many_maximum = Field::MANY_MAXIMUM, |
| 86 | + public int $minimum = 0, |
| 87 | + public int $maximum = PHP_INT_MAX, |
| 88 | + string|null $delimiter = ',', |
| 89 | + string $verbose_name = '', |
| 90 | + string $verbose_name_plural = '', |
| 91 | + string $internal_name = '', |
| 92 | + string $internal_namespace = '', |
| 93 | + array $referenced_by = [], |
| 94 | + array $conditions = [], |
| 95 | + array $validators = [], |
| 96 | + string $help_text = '', |
| 97 | + ) { |
| 98 | + parent::__construct( |
| 99 | + type: 'integer', |
| 100 | + required: $required, |
| 101 | + unique: $unique, |
| 102 | + default: $default, |
| 103 | + default_callable: $default_callable, |
| 104 | + choices: $choices, |
| 105 | + choices_callable: $choices_callable, |
| 106 | + allow_null: $allow_null, |
| 107 | + editable: $editable, |
| 108 | + read_only: $read_only, |
| 109 | + write_only: $write_only, |
| 110 | + representation_only: $representation_only, |
| 111 | + many: $many, |
| 112 | + many_minimum: $many_minimum, |
| 113 | + many_maximum: $many_maximum, |
| 114 | + delimiter: $delimiter, |
| 115 | + verbose_name: $verbose_name, |
| 116 | + verbose_name_plural: $verbose_name_plural, |
| 117 | + internal_name: $internal_name, |
| 118 | + internal_namespace: $internal_namespace, |
| 119 | + referenced_by: $referenced_by, |
| 120 | + conditions: $conditions, |
| 121 | + validators: $validators + [ |
| 122 | + new RESTAPI\Validators\NumericRangeValidator(minimum: $minimum, maximum: $maximum), |
| 123 | + ], |
| 124 | + help_text: $help_text, |
| 125 | + ); |
| 126 | + } |
| 127 | + |
| 128 | + /** |
| 129 | + * Converts the field value from its representation value into it's internal value. This namely handles converting |
| 130 | + * 0 to 'auto'. |
| 131 | + * @param mixed $representation_value The representation value to convert to its internal value |
| 132 | + */ |
| 133 | + protected function _to_internal(mixed $representation_value): array|string|null { |
| 134 | + if ($representation_value === 0) { |
| 135 | + return parent::_to_internal('auto'); |
| 136 | + } |
| 137 | + return parent::_to_internal($representation_value); |
| 138 | + } |
| 139 | + |
| 140 | + /** |
| 141 | + * Converts the field value to its representation form from its internal pfSense configuration value. |
| 142 | + * @param string $internal_value The internal value from the pfSense configuration. |
| 143 | + * @return int The field value in its representation form. |
| 144 | + */ |
| 145 | + protected function _from_internal(mixed $internal_value): mixed { |
| 146 | + # Return the value as an integer if it's numeric |
| 147 | + if (is_numeric($internal_value)) { |
| 148 | + return intval($internal_value); |
| 149 | + } |
| 150 | + |
| 151 | + # If the value is 'auto', return 0 (0 is the representation we use for auto) |
| 152 | + if ($internal_value === 'auto') { |
| 153 | + return 0; |
| 154 | + } |
| 155 | + |
| 156 | + # If the value is an empty string, assume it's null |
| 157 | + if ($internal_value === '') { |
| 158 | + return null; |
| 159 | + } |
| 160 | + |
| 161 | + # Otherwise, the internal value cannot be represented by this Field. Throw an error. |
| 162 | + throw new RESTAPI\Responses\ServerError( |
| 163 | + message: "Cannot parse KeyLenField '$this->name' from internal because its internal value is not a " . |
| 164 | + "numeric value or 'auto'. Consider changing this field to a StringField.", |
| 165 | + response_id: 'KEYLEN_FIELD_WITH_NON_INTEGER_INTERNAL_VALUE', |
| 166 | + ); |
| 167 | + } |
| 168 | + |
| 169 | + /** |
| 170 | + * Converts this Field object to a PHP array representation of an OpenAPI schema property configuration. This is |
| 171 | + * used when auto-generating API documentation. This method can be extended to add additional options to the OpenAPI |
| 172 | + * schema property. |
| 173 | + * @link https://swagger.io/docs/specification/data-models/ |
| 174 | + * @return array A PHP array containing this field as a OpenAPI schema property configuration. |
| 175 | + */ |
| 176 | + public function to_openapi_property(): array { |
| 177 | + # Run the parent to_openapi_property() to obtain the base property object, then make changes as needed. |
| 178 | + $openapi_property = parent::to_openapi_property(); |
| 179 | + |
| 180 | + # Add the minimum and maximum to the OpenAPI property. |
| 181 | + if ($this->many) { |
| 182 | + $openapi_property['items']['minimum'] = $this->minimum; |
| 183 | + $openapi_property['items']['maximum'] = $this->maximum; |
| 184 | + } else { |
| 185 | + $openapi_property['minimum'] = $this->minimum; |
| 186 | + $openapi_property['maximum'] = $this->maximum; |
| 187 | + } |
| 188 | + |
| 189 | + return $openapi_property; |
| 190 | + } |
| 191 | + |
| 192 | + /** |
| 193 | + * Converts this Field object into a pfSense webConfigurator form input. This method can be overridden by a child |
| 194 | + * class to add custom input field creation. |
| 195 | + * @param string $type The HTML input tag type. Not all Fields support input types. |
| 196 | + * @param array $attributes An array of additional HTML input tag attributes. Not all Fields support input attributes. |
| 197 | + * @return object The pfSense webConfigurator form input object. |
| 198 | + * @link https://github.com/pfsense/pfsense/tree/master/src/usr/local/www/classes/Form |
| 199 | + */ |
| 200 | + public function to_form_input(string $type = 'number', array $attributes = []): object { |
| 201 | + $attributes += ['min' => $this->minimum, 'max' => $this->maximum]; |
| 202 | + return parent::to_form_input(type: $type, attributes: $attributes); |
| 203 | + } |
| 204 | +} |
0 commit comments