<commit_before><?php namespace NZTim\Input;

use Carbon\Carbon;
use Illuminate\Http\Request;
use InvalidArgumentException;
use Validator as LaravelValidator;
use Illuminate\Contracts\Validation\Validator as ValidatorContract;

abstract class BaseProcessor
{
    protected $input;
    protected $validation;

    // Data and overrides -----------------------------------------------------

    protected $defaultMessages = [
        'required'     => 'This field is required',
        'in'           => 'Please make a selection', // Used for select inputs
        'email'        => 'Please enter a valid email address',
        'email.unique' => 'This email address is already registered',
    ];

    abstract protected function rules() : array;

    protected function messages() : array
    {
        return [];
    }

    protected function casts() : array
    {
        return [];
    }

    // Public methods ---------------------------------------------------------

    public function __construct(Request $request)
    {
        $this->input = $this->normalize($request->all());
    }

    public function setInput(string $key, $value)
    {
        $this->input[$key] = $value;
    }

    public function removeInput(string $key)
    {
        unset($this->input[$key]);
    }

    public function replaceInput(array $input)
    {
        $this->input = $this->normalize($input);
    }

    /**
     * Accepts optional rules and messages arrays, how they are handled depends on $merge parameter
     * $merge determines if the provided rules are merged with or replace the existing rules
     * @param array $rules
     * @param array $messages
     * @param bool $merge
     * @return bool
     */
    public function validate(array $rules = [], array $messages = [], bool $merge = true) : bool
    {
        if ($merge) {
            $rules = array_merge($this->rules(), $rules);
            $messages = array_merge($this->defaultMessages, $this->messages(), $messages);
        }
        $rules = $this->uniqueUpdates($rules);
        $validation = LaravelValidator::make($this->input, $rules, $messages);
        if ($validation->fails()) {
            $this->validation = $validation;
            return false;
        } else {
            $this->validation = false;
            return true;
        }
    }

    /**
     * @return \Illuminate\Validation\Validator
     */
    public function getValidation()
    {
        if (is_null($this->validation)) {
            $this->validate();
        }
        return $this->validation;
    }

    public function getInput(bool $cast = true) : array
    {
        return $cast ? $this->castInput() : $this->input;
    }

    // ------------------------------------------------------------------------

    /**
     * Remove unexpected fields and ensure all fields in rules array are present
     * @param $input
     * @return array
     */
    protected function normalize(array $input) : array
    {
        $normalized = [];
        foreach ($this->rules() as $field => $value) {
            $normalized[$field] = $input[$field] ?? '';
        }
        return $normalized;
    }

    /**
     * Updates the rules array to handle unique updates
     * Example rule: 'email' => 'required|integer|unique:users,email,{:id}'
     * If $input['id'] is set, i.e. input has an ID, then ',{:id}' is replaced with the ID, e.g. ',123'
     * If $input['id'] is not set then the extra part of the rule ',{:id}' is removed
     * @param array $rules
     * @return array
     */
    protected function uniqueUpdates($rules) : array
    {
        $replace = empty($this->input['id']) ? '' : ',' . $this->input['id'];
        $output = [];
        foreach ($rules as $key => $rule) {
            $output[$key] = str_replace(',{:id}', $replace, $rule);
        }
        return $output;
    }

    /**
     * @throws InvalidArgumentException
     * @return array
     */
    protected function castInput() : array
    {
        $output = [];
        $casts = $this->casts();
        foreach($this->input as $key => $value) {
            if (!isset($casts[$key])) {
                $output[$key] = $value;
                continue;
            }
            if (is_callable($casts[$key])) {
                $output[$key] = $casts[$key]($value);
            }
            if ($casts[$key] == 'int') {
                $output[$key] = intval($value);
            }
            if ($casts[$key] == 'bool') {
                $output[$key] = (bool) $value;
            }
            if ($casts[$key] == 'float') {
                $output[$key] = floatval($value);
            }
            if ($casts[$key] == 'carbon') {
                $output[$key] = Carbon::parse($value);
            }
            if (!isset($output[$key])) {
                throw new InvalidArgumentException('$casts array value for '. $key . ' is not valid: ' . $value);
            }
        }<commit_msg>Remove facade, formatting<commit_after><?php namespace NZTim\Input;

use Carbon\Carbon;
use Illuminate\Http\Request;
use \Illuminate\Validation\Factory;
use Illuminate\Validation\Validator;

use InvalidArgumentException;

abstract class BaseProcessor
{
    protected $input;
    protected $validation;
    protected $laravelValidation;

    // Data and overrides -----------------------------------------------------

    protected $defaultMessages = [
        'required'     => 'This field is required',
        'in'           => 'Please make a selection', // Used for select inputs
        'email'        => 'Please enter a valid email address',
        'email.unique' => 'This email address is already registered',
    ];

    abstract protected function rules(): array;

    protected function messages(): array
    {
        return [];
    }

    protected function casts(): array
    {
        return [];
    }

    // Public methods ---------------------------------------------------------

    public function __construct(Request $request, Factory $laravelValidation)
    {
        $this->input = $this->normalize($request->all());
        $this->laravelValidation = $laravelValidation;
    }

    public function setInput(string $key, $value)
    {
        $this->input[$key] = $value;
    }

    public function removeInput(string $key)
    {
        unset($this->input[$key]);
    }

    public function replaceInput(array $input)
    {
        $this->input = $this->normalize($input);
    }

    /**
     * Accepts optional rules and messages arrays
     * $merge = true - rules are merged with existing rules
     * $merge = false - existing rules are ignored
     */
    public function validate(array $rules = [], array $messages = [], bool $merge = true): bool
    {
        if ($merge) {
            $rules = array_merge($this->rules(), $rules);
            $messages = array_merge($this->defaultMessages, $this->messages(), $messages);
        }
        $rules = $this->uniqueUpdates($rules);
        $validation = $this->laravelValidation->make($this->input, $rules, $messages);
        if ($validation->fails()) {
            $this->validation = $validation;
            return false;
        } else {
            $this->validation = false;
            return true;
        }
    }

    public function getValidation(): Validator
    {
        if (is_null($this->validation)) {
            $this->validate();
        }
        return $this->validation;
    }

    public function getInput(bool $cast = true): array
    {
        return $cast ? $this->castInput() : $this->input;
    }

    // ------------------------------------------------------------------------

    // Remove unexpected fields and ensure all fields in rules array are present
    protected function normalize(array $input): array
    {
        $normalized = [];
        foreach ($this->rules() as $field => $value) {
            $normalized[$field] = $input[$field] ?? '';
        }
        return $normalized;
    }

    /**
     * Updates the rules array to handle unique updates
     * Example rule: 'email' => 'required|integer|unique:users,email,{:id}'
     * If $input['id'] is set, i.e. input has an ID, then ',{:id}' is replaced with the ID, e.g. ',123'
     * If $input['id'] is not set then the extra part of the rule ',{:id}' is removed
     */
    protected function uniqueUpdates(array $rules): array
    {
        $replace = empty($this->input['id']) ? '' : ',' . $this->input['id'];
        $output = [];
        foreach ($rules as $key => $rule) {
            $output[$key] = str_replace(',{:id}', $replace, $rule);
        }
        return $output;
    }

    protected function castInput(): array
    {
        $output = [];
        $casts = $this->casts();
        foreach ($this->input as $key => $value) {
            if (!isset($casts[$key])) {
                $output[$key] = $value;
                continue;
            }
            if (is_callable($casts[$key])) {
                $output[$key] = $casts[$key]($value);
            }
            if ($casts[$key] == 'int') {
                $output[$key] = intval($value);
            }
            if ($casts[$key] == 'bool') {
                $output[$key] = (bool) $value;
            }
            if ($casts[$key] == 'float') {
                $output[$key] = floatval($value);
            }
            if ($casts[$key] == 'carbon') {
                $output[$key] = Carbon::parse($value);
            }
            if (!isset($output[$key])) {
                throw new InvalidArgumentException('$casts array value for ' . $key . ' is not valid: ' . $value);
            }
        }
{'fraction_non_alphanumeric': 0.17966384800083515, 'fraction_numerical': 0.0006263701847792045, 'mean_word_length': 1.7856935155568479, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 72, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2810594', 'n_tokens_mistral': 2580, 'n_tokens_neox': 2502, 'n_words': 675}