| 
<?phpdeclare(strict_types=1);
 namespace ParagonIE\Ionizer;
 
 use ParagonIE\ConstantTime\Binary;
 use ParagonIE\Ionizer\Contract\FilterInterface;
 
 /**
 * Class InputFilter
 * @package ParagonIE\Ionizer
 */
 class InputFilter implements FilterInterface
 {
 /**
 * @var string|int|float|bool|array|null
 */
 protected $default;
 
 /**
 * @var string
 */
 protected $type = '';
 
 /**
 * @var string (for debugging purposes)
 */
 protected $index = '';
 
 /**
 * @var callable[]
 */
 protected $callbacks = [];
 
 /**
 * @var string[]
 */
 protected $thisCallbacks = [];
 
 /**
 * Sets the expected input type (e.g. string, boolean)
 *
 * @param string $typeIndicator
 * @return FilterInterface
 */
 public function setType(string $typeIndicator): FilterInterface
 {
 $this->type = $typeIndicator;
 return $this;
 }
 
 /**
 * Throw an InvalidDataException is this field is not defined/populated.
 * Use in a callback.
 *
 * $filter->addCallback([InputFilter::class, 'required']);
 *
 * @param mixed|null $data
 * @return mixed
 * @throws InvalidDataException
 */
 public static function required($data = null)
 {
 if (\is_null($data)) {
 throw new InvalidDataException('This is not an optional field.');
 }
 return $data;
 }
 
 /**
 * Set the default value (not applicable to booleans)
 *
 * @param string|int|float|bool|array|null $value
 * @return FilterInterface
 */
 public function setDefault($value): FilterInterface
 {
 $this->default = $value;
 return $this;
 }
 
 /**
 * Add a callback to this filter (supports more than one)
 *
 * @param callable $func
 * @return FilterInterface
 */
 public function addCallback(callable $func): FilterInterface
 {
 $this->callbacks[] = $func;
 return $this;
 }
 
 /**
 * Add a callback to this filter (supports more than one)
 *
 * @param string $func
 * @return FilterInterface
 */
 public function addThisCallback(string $func): FilterInterface
 {
 if (!\method_exists($this, $func)) {
 throw new \Error('Method ' . $func . ' does not exist on class ' . \get_class($this));
 }
 $this->thisCallbacks[] = $func;
 return $this;
 }
 
 /**
 * Process data using the filter rules.
 *
 * @param mixed $data
 * @return mixed
 * @throws InvalidDataException
 * @throws \TypeError
 */
 public function process($data = null)
 {
 /** @var string|int|float|bool|array|null $data */
 $data = $this->applyCallbacks($data, 0);
 /** @var string|int|float|bool|array|null $data */
 $data = $this->applyThisCallbacks($data, 0);
 if ($data === null) {
 /** @var string|int|float|bool|array|null $data */
 $data = $this->default;
 }
 
 // For type strictness:
 switch ($this->type) {
 case 'array':
 /** @var array $data */
 return (array) $data;
 case 'bool':
 /** @var bool $data */
 return (bool) $data;
 case 'float':
 /** @var float $data */
 return (float) $data;
 case 'int':
 /** @var int $data */
 return (int) $data;
 case 'string':
 /** @var string $data */
 return (string) $data;
 default:
 return $data;
 }
 }
 
 /**
 * Apply all of the callbacks for this filter.
 *
 * @param mixed $data
 * @param int $offset
 * @return mixed
 * @throws InvalidDataException
 */
 public function applyCallbacks($data = null, int $offset = 0)
 {
 if (empty($data)) {
 if ($this->type === 'bool') {
 return false;
 }
 return $this->default;
 }
 if ($offset >= \count($this->callbacks)) {
 return $data;
 }
 $func = $this->callbacks[$offset];
 /** @var string|int|float|bool|array|null $data */
 $data = $func($data);
 return $this->applyCallbacks($data, $offset + 1);
 }
 /**
 * Apply all of the callbacks for this filter.
 *
 * @param mixed $data
 * @param int $offset
 * @return mixed
 * @throws InvalidDataException
 */
 public function applyThisCallbacks($data = null, int $offset = 0)
 {
 if ($offset >= \count($this->thisCallbacks)) {
 return $data;
 }
 /** @var string $func */
 $func = $this->thisCallbacks[$offset];
 /** @var string|int|float|bool|array|null $data */
 $data = $this->$func($data);
 return $this->applyCallbacks($data, $offset + 1);
 }
 
 /**
 * @param string $index
 * @return FilterInterface
 */
 public function setIndex(string $index): FilterInterface
 {
 $this->index = $index;
 return $this;
 }
 }
 
 |