<commit_before><?php
namespace Czim\NestedModelUpdater;

use Czim\NestedModelUpdater\Contracts\NestedValidatorInterface;
use Czim\NestedModelUpdater\Data\RelationInfo;
use Illuminate\Contracts\Container\BindingResolutionException;
use Illuminate\Contracts\Validation\Factory;
use Illuminate\Support\Facades\App;
use Illuminate\Support\MessageBag;
use ReflectionException;
use UnexpectedValueException;

class NestedValidator extends AbstractNestedParser implements NestedValidatorInterface
{

    /**
     * @var bool
     */
    protected $validates = true;

    /**
     * @var \Illuminate\Contracts\Support\MessageBag
     */
    protected $messages;



    /**
     * Performs validation and returns whether it succeeds.
     *
     * @param array $data
     * @param bool  $creating   if false, validate for update
     * @return bool
     */
    public function validate(array $data, $creating = true)
    {
        $this->relationsAnalyzed = false;

        $this->validates  = true;
        $this->messages   = app(MessageBag::class);
        $this->data       = $data;
        $this->model      = null;

        $rules = $this->getValidationRules($creating);
        
        $validator = $this->getValidationFactory()->make($data, $rules);

        if ($validator->fails()) {
            $this->validates = false;
            $this->messages  = $validator->getMessageBag();
        }

        return $this->validates;
    }

    /**
     * Returns validation rules array for full nested data.
     *
     * @param array $data
     * @param bool  $creating
     * @return array
     */
    public function validationRules(array $data, $creating = true)
    {
        $this->relationsAnalyzed = false;

        $this->data = $data;

        return $this->getValidationRules($creating);
    }

    /**
     * Returns validation messages, if validation has been performed.
     *
     * @return null|\Illuminate\Contracts\Support\MessageBag
     */
    public function messages()
    {
        return $this->messages;
    }

    /**
     * Returns validation rules for the current model only
     *
     * @param bool $prefixNesting if true, prefixes the validation rules with the relevant key nesting.
     * @param bool $creating
     * @return array
     */
    public function getDirectModelValidationRules($prefixNesting = false, $creating = true)
    {
        $rulesInstance = $this->makeModelRulesInstance();

        if ( ! $rulesInstance) {
            return [];
        }

        $method = $this->determineModelRulesMethod();

        if ( ! method_exists($rulesInstance, $method)) {
            throw new UnexpectedValueException(get_class($rulesInstance) . " has no method '{$method}'");
        }

        $rules = $rulesInstance->{$method}($creating ? 'create' : 'update');

        if ( ! is_array($rules)) {
            throw new UnexpectedValueException(get_class($rulesInstance) . "::{$method} did not return array");
        }

        if ($prefixNesting) {
            $rules = $this->prefixAllKeysInArray($rules);
        }

        return $rules;
    }

    /**
     * Returns nested validation rules for the entire nested data structure.
     *
     * @param bool  $creating
     * @return array
     */
    protected function getValidationRules($creating = true)
    {
        $this->config->setParentModel($this->modelClass);
        $this->analyzeNestedRelationsData();

        // get validation rules for this model/level,
        // prepend keys correctly with current nested key & index

        $rules = $this->getDirectModelValidationRules(true, $creating);

        // for any child relations, created a nested validator
        // and merge its validation rules

        $rules = array_merge($rules, $this->getNestedRelationValidationRules());

        return $rules;
    }

    /**
     * @return array
     */
    protected function getNestedRelationValidationRules()
    {
        $rules = [];


        foreach ($this->relationInfo as $attribute => $info) {
            if ( ! array_has($this->data, $attribute)) continue;

            if ( ! $info->isSingular()) {
                // make sure we force an array if we're expecting a plural relation,
                // and make data-based rules for each item in the array

                $rules[ $this->getNestedKeyPrefix() . $attribute ] = 'array';
                
                if (is_array($this->data[ $attribute ])) {
                    for ($index = 0; $index < count($this->data[ $attribute ]); $index++) {

                        $rules = array_merge($rules, $this->getNestedRelationValidationRulesForSingleItem($info, $attribute, $index));
                    }
                }

            } else {

                $rules = array_merge($rules, $this->getNestedRelationValidationRulesForSingleItem($info, $attribute));
            }
        }

        return $rules;
    }

    /**
     * @param RelationInfo $info
     * @param string       $attribute   key of attribute
     * @param null|int     $index       if data is plural for this attribute, the index for it
     * @return array
     */
    protected function getNestedRelationValidationRulesForSingleItem(RelationInfo $info, $attribute, $index = null)<commit_msg>minor validator tweak (sensiolabs)<commit_after><?php
namespace Czim\NestedModelUpdater;

use Czim\NestedModelUpdater\Contracts\NestedValidatorInterface;
use Czim\NestedModelUpdater\Data\RelationInfo;
use Illuminate\Contracts\Container\BindingResolutionException;
use Illuminate\Contracts\Validation\Factory;
use Illuminate\Support\Facades\App;
use Illuminate\Support\MessageBag;
use ReflectionException;
use UnexpectedValueException;

class NestedValidator extends AbstractNestedParser implements NestedValidatorInterface
{

    /**
     * @var bool
     */
    protected $validates = true;

    /**
     * @var \Illuminate\Contracts\Support\MessageBag
     */
    protected $messages;



    /**
     * Performs validation and returns whether it succeeds.
     *
     * @param array $data
     * @param bool  $creating   if false, validate for update
     * @return bool
     */
    public function validate(array $data, $creating = true)
    {
        $this->relationsAnalyzed = false;

        $this->validates  = true;
        $this->messages   = app(MessageBag::class);
        $this->data       = $data;
        $this->model      = null;

        $rules = $this->getValidationRules($creating);
        
        $validator = $this->getValidationFactory()->make($data, $rules);

        if ($validator->fails()) {
            $this->validates = false;
            $this->messages  = $validator->getMessageBag();
        }

        return $this->validates;
    }

    /**
     * Returns validation rules array for full nested data.
     *
     * @param array $data
     * @param bool  $creating
     * @return array
     */
    public function validationRules(array $data, $creating = true)
    {
        $this->relationsAnalyzed = false;

        $this->data = $data;

        return $this->getValidationRules($creating);
    }

    /**
     * Returns validation messages, if validation has been performed.
     *
     * @return null|\Illuminate\Contracts\Support\MessageBag
     */
    public function messages()
    {
        return $this->messages;
    }

    /**
     * Returns validation rules for the current model only
     *
     * @param bool $prefixNesting if true, prefixes the validation rules with the relevant key nesting.
     * @param bool $creating
     * @return array
     */
    public function getDirectModelValidationRules($prefixNesting = false, $creating = true)
    {
        $rulesInstance = $this->makeModelRulesInstance();

        if ( ! $rulesInstance) {
            return [];
        }

        $method = $this->determineModelRulesMethod();

        if ( ! method_exists($rulesInstance, $method)) {
            throw new UnexpectedValueException(get_class($rulesInstance) . " has no method '{$method}'");
        }

        $rules = $rulesInstance->{$method}($creating ? 'create' : 'update');

        if ( ! is_array($rules)) {
            throw new UnexpectedValueException(get_class($rulesInstance) . "::{$method} did not return array");
        }

        if ($prefixNesting) {
            $rules = $this->prefixAllKeysInArray($rules);
        }

        return $rules;
    }

    /**
     * Returns nested validation rules for the entire nested data structure.
     *
     * @param bool  $creating
     * @return array
     */
    protected function getValidationRules($creating = true)
    {
        $this->config->setParentModel($this->modelClass);
        $this->analyzeNestedRelationsData();

        // get validation rules for this model/level,
        // prepend keys correctly with current nested key & index

        $rules = $this->getDirectModelValidationRules(true, $creating);

        // for any child relations, created a nested validator
        // and merge its validation rules

        $rules = array_merge($rules, $this->getNestedRelationValidationRules());

        return $rules;
    }

    /**
     * @return array
     */
    protected function getNestedRelationValidationRules()
    {
        $rules = [];


        foreach ($this->relationInfo as $attribute => $info) {
            if ( ! array_has($this->data, $attribute)) continue;

            if ( ! $info->isSingular()) {
                // make sure we force an array if we're expecting a plural relation,
                // and make data-based rules for each item in the array

                $rules[ $this->getNestedKeyPrefix() . $attribute ] = 'array';
                
                if (is_array($this->data[ $attribute ])) {

                    $total = count($this->data[ $attribute ]);
                    for ($index = 0; $index < $total; $index++) {

                        $rules = array_merge($rules, $this->getNestedRelationValidationRulesForSingleItem($info, $attribute, $index));
                    }
                }

            } else {

                $rules = array_merge($rules, $this->getNestedRelationValidationRulesForSingleItem($info, $attribute));
            }
        }

        return $rules;
    }

    /**
     * @param RelationInfo $info
     * @param string       $attribute   key of attribute
     * @param null|int     $index       if data is plural for this attribute, the index for it
     * @return array
     */
    protected function getNestedRelationValidationRulesForSingleItem(RelationInfo $info, $attribute, $index = null)
{'fraction_non_alphanumeric': 0.11369459998101926, 'fraction_numerical': 0.00018980734554427256, 'mean_word_length': 2.2787803360298695, 'pattern_counts': {'":': 2, '<': 7, '<?xml version=': 0, '>': 75, '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': '4376047', 'n_tokens_mistral': 2867, 'n_tokens_neox': 2792, 'n_words': 702}