<commit_before><?php

namespace SleepingOwl\Admin\Form\Related\Forms;

use Admin\Contracts\HasFakeModel;
use Exception;
use Illuminate\Contracts\Support\Htmlable;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Http\Request;
use Illuminate\Support\Arr;
use Illuminate\Support\Collection;
use KodiComponents\Support\HtmlAttributes;
use SleepingOwl\Admin\Contracts\Form\Columns\ColumnInterface;
use SleepingOwl\Admin\Contracts\Initializable;
use SleepingOwl\Admin\Exceptions\Form\FormElementException;
use SleepingOwl\Admin\Form\Columns\Columns;
use SleepingOwl\Admin\Form\Element\Custom;
use SleepingOwl\Admin\Form\Element\DependentSelect;
use SleepingOwl\Admin\Form\Element\File;
use SleepingOwl\Admin\Form\Element\Files;
use SleepingOwl\Admin\Form\Element\Image;
use SleepingOwl\Admin\Form\Element\MultiDependentSelect;
use SleepingOwl\Admin\Form\Element\NamedFormElement;
use SleepingOwl\Admin\Form\Element\Textarea;
use SleepingOwl\Admin\Form\FormElements;
use SleepingOwl\Admin\Form\Related\Group;
use SleepingOwl\Admin\Form\Related\HasUniqueValidation;
use SleepingOwl\Admin\Form\Related\ManipulatesRequestRelations;

class HasManyLocal extends FormElements
{
    use HtmlAttributes, HasUniqueValidation, ManipulatesRequestRelations;

    protected $view = 'form.element.related.elements';

    const NEW_ITEM = 'new';

    const REMOVE = 'remove';

    /**
     * How many items can be created.
     *
     * @var int
     */
    protected $limit;

    /**
     * New records counter.
     *
     * @var int
     */
    protected $new = 0;

    /**
     * @var string
     */
    protected $groupLabel;

    /**
     * Main label of dynamic form.
     *
     * @var string
     */
    protected $label;

    /**
     * Loaded related values.
     *
     * @var \Illuminate\Support\Collection
     */
    protected $fieldValues;

    /**
     * @var \Illuminate\Database\Eloquent\Model
     */
    protected $instance;

    protected $stubElements;

    /**
     * Elements that are about to be removed.
     *
     * @var \Illuminate\Support\Collection
     */
    protected $toRemove;

    protected $unique;

    /**
     * @var
     */
    protected $groups;

    protected $transactionLevel;

    /**
     * @var string
     */
    protected $fieldName;

    /**
     * @var string
     */
    protected $helpText;

    /**
     * @var null|callable
     */
    protected $saveCallback = null;

    /**
     * @var null|callable
     */
    protected $loadCallback = null;

    /**
     * @var int
     */
    protected $jsonOptions = 0;

    /**
     * @var string
     */
    protected $saveMode = 'json';

    /**
     * @var bool
     */
    // protected $needToSetValueSkipped = false;

    /**
     * @var callable|null|false
     */
    // protected $emptyElementCallback;

    /**
     * HasManyLocal constructor.
     *
     * @param string $fieldName
     * @param array  $elements
     * @param string $label
     */
    public function __construct(string $fieldName, array $elements = [], $label = '')
    {
        $this->toRemove = collect();
        $this->groups = collect();
        $this->fieldValues = collect();
        $this->setLabel($label);

        parent::__construct($elements);

        $this->setFieldName($fieldName);
    }

    /**
     * @param int $limit
     *
     * @return $this
     */
    public function setLimit(int $limit): self
    {
        $this->limit = $limit;

        return $this;
    }

    /**
     * @param string $label
     *
     * @return $this
     */
    public function setLabel(string $label): self
    {
        $this->label = $label;

        return $this;
    }

    public function initialize()
    {
        parent::initialize();

        $this->stubElements = $this->getNewElements();
        $this->forEachElement($this->stubElements, function ($element) {
            //$element->setDefaultValue(null);
            if (! $element instanceof HasFakeModel) {
                if (! $element instanceof Image && ! $element instanceof Textarea && ! $element instanceof File) {
                    $element->setPath('');
                }

                // Disabled elements for using inside hasManyLocal
                $disabledElements = [
                    Files::class => 'files',
                    DependentSelect::class => 'dependentselect',
                    MultiDependentSelect::class => 'multidependentselect',
                ];
                foreach ($disabledElements as $elementClass => $elementName) {
                    if ($element instanceof $elementClass) {
                        throw new FormElementException('Form element ['.$elementName.'] is not implemented to use inside hasManyLocal yet, sorry');
                    }
                }
            }
        });
    }

    /**
     * @return void
     */
    public function initializeElements()
    {
        $this->getElements()->each(function ($el) {
            $this->initializeElement($el);
        });
    }

    public function initializeElement($element)
    {
        //ignore second initialize
        if ($element instanceof ColumnInterface) {
            return;
        }

        if ($element instanceof Initializable) {
            $element->initialize();
        }

        if ($element instanceof HasFakeModel) {
            $element->setFakeModel($this->getModel());
        }
    }

    protected function getNewElements(): Collection
    {
        return $this->cloneElements($this);
    }

    protected function cloneElements(FormElements $element)
    {
        $elements = clone $element->getElements()->map(function ($element) {
            return is_object($element) ? clone $element : $element;
        });

        return $elements->map(function ($element) {
            return $this->emptyElement($element);
        });
    }

    /**
     * @param $element
     *
     * @return Columns|Custom|FormElements
     * @throws Exception
     */
    protected function emptyElement($element)
    {
        $el = is_object($element) ? clone $element : $element;

        if ($el instanceof Columns) {
            $col = new Columns();
            $columns = $el->getElements();
            $columns = (clone $columns)->map(function ($column) {
                return $this->emptyElement($column);
            });
            foreach ($columns as $column) {
                $col->addColumn($column, $column->getWidth());
            }

            $col->setHtmlAttributes($el->getHtmlAttributes());
            $col->initialize();

            return $col;
        }

        if ($el instanceof FormElements) {
            $el->setElements($this->cloneElements($el)->all());
        } else {
            if (! ($el instanceof Custom)) {
                //$el->setDefaultValue(null);
            }

            // Save process: v2
            // if (is_object($el) && $this->needToSetValueSkipped()) {
            //     $el->setValueSkipped(true);
            // }
        }

        // Save process: v2
        // if (is_callable($this->emptyElementCallback)) {
        //     call_user_func($this->emptyElementCallback, $el);
        // }

        return $el;
    }

    /**
     * @param Model $model
     *
     * @return FormElements|void
     * @throws \Illuminate\Database\Eloquent\ModelNotFoundException
     */
    public function setModel(Model $model)
    {
        parent::setModel($model);

        if ($model->exists) {
            $this->setInstance($model);
            $this->loadFieldValues();
        }
    }

    public function setInstance($instance)
    {
        $this->instance = $instance;
    }

    /**
     * Sets field name property.
     *
     * @param string
     *
     * @return HasManyLocal
     */
    public function setFieldName(string $name): self
    {
        $this->fieldName = $name;

        return $this;
    }

    public function getFieldName(): string
    {
        return $this->fieldName;
    }

    /**
     * @throws Exception
     */
    protected function loadFieldValues()
    {
        $this->fieldValues = $this->getFieldValues();<commit_msg>HasManyLocal: getInstance() method, logic for setModel() from getInstance() for manually use<commit_after><?php

namespace SleepingOwl\Admin\Form\Related\Forms;

use Admin\Contracts\HasFakeModel;
use Exception;
use Illuminate\Contracts\Support\Htmlable;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Http\Request;
use Illuminate\Support\Arr;
use Illuminate\Support\Collection;
use KodiComponents\Support\HtmlAttributes;
use SleepingOwl\Admin\Contracts\Form\Columns\ColumnInterface;
use SleepingOwl\Admin\Contracts\Initializable;
use SleepingOwl\Admin\Exceptions\Form\FormElementException;
use SleepingOwl\Admin\Form\Columns\Columns;
use SleepingOwl\Admin\Form\Element\Custom;
use SleepingOwl\Admin\Form\Element\DependentSelect;
use SleepingOwl\Admin\Form\Element\File;
use SleepingOwl\Admin\Form\Element\Files;
use SleepingOwl\Admin\Form\Element\Image;
use SleepingOwl\Admin\Form\Element\MultiDependentSelect;
use SleepingOwl\Admin\Form\Element\NamedFormElement;
use SleepingOwl\Admin\Form\Element\Textarea;
use SleepingOwl\Admin\Form\FormElements;
use SleepingOwl\Admin\Form\Related\Group;
use SleepingOwl\Admin\Form\Related\HasUniqueValidation;
use SleepingOwl\Admin\Form\Related\ManipulatesRequestRelations;

class HasManyLocal extends FormElements
{
    use HtmlAttributes, HasUniqueValidation, ManipulatesRequestRelations;

    protected $view = 'form.element.related.elements';

    const NEW_ITEM = 'new';

    const REMOVE = 'remove';

    /**
     * How many items can be created.
     *
     * @var int
     */
    protected $limit;

    /**
     * New records counter.
     *
     * @var int
     */
    protected $new = 0;

    /**
     * @var string
     */
    protected $groupLabel;

    /**
     * Main label of dynamic form.
     *
     * @var string
     */
    protected $label;

    /**
     * Loaded related values.
     *
     * @var \Illuminate\Support\Collection
     */
    protected $fieldValues;

    /**
     * @var \Illuminate\Database\Eloquent\Model
     */
    protected $instance;

    protected $stubElements;

    /**
     * Elements that are about to be removed.
     *
     * @var \Illuminate\Support\Collection
     */
    protected $toRemove;

    protected $unique;

    /**
     * @var
     */
    protected $groups;

    protected $transactionLevel;

    /**
     * @var string
     */
    protected $fieldName;

    /**
     * @var string
     */
    protected $helpText;

    /**
     * @var null|callable
     */
    protected $saveCallback = null;

    /**
     * @var null|callable
     */
    protected $loadCallback = null;

    /**
     * @var int
     */
    protected $jsonOptions = 0;

    /**
     * @var string
     */
    protected $saveMode = 'json';

    /**
     * @var bool
     */
    // protected $needToSetValueSkipped = false;

    /**
     * @var callable|null|false
     */
    // protected $emptyElementCallback;

    /**
     * HasManyLocal constructor.
     *
     * @param string $fieldName
     * @param array  $elements
     * @param string $label
     */
    public function __construct(string $fieldName, array $elements = [], $label = '')
    {
        $this->toRemove = collect();
        $this->groups = collect();
        $this->fieldValues = collect();
        $this->setLabel($label);

        parent::__construct($elements);

        $this->setFieldName($fieldName);
    }

    /**
     * @param int $limit
     *
     * @return $this
     */
    public function setLimit(int $limit): self
    {
        $this->limit = $limit;

        return $this;
    }

    /**
     * @param string $label
     *
     * @return $this
     */
    public function setLabel(string $label): self
    {
        $this->label = $label;

        return $this;
    }

    public function initialize()
    {
        parent::initialize();

        $this->stubElements = $this->getNewElements();
        $this->forEachElement($this->stubElements, function ($element) {
            //$element->setDefaultValue(null);
            if (! $element instanceof HasFakeModel) {
                if (! $element instanceof Image && ! $element instanceof Textarea && ! $element instanceof File) {
                    $element->setPath('');
                }

                // Disabled elements for using inside hasManyLocal
                $disabledElements = [
                    Files::class => 'files',
                    DependentSelect::class => 'dependentselect',
                    MultiDependentSelect::class => 'multidependentselect',
                ];
                foreach ($disabledElements as $elementClass => $elementName) {
                    if ($element instanceof $elementClass) {
                        throw new FormElementException('Form element ['.$elementName.'] is not implemented to use inside hasManyLocal yet, sorry');
                    }
                }
            }
        });
    }

    /**
     * @return void
     */
    public function initializeElements()
    {
        $this->getElements()->each(function ($el) {
            $this->initializeElement($el);
        });
    }

    public function initializeElement($element)
    {
        //ignore second initialize
        if ($element instanceof ColumnInterface) {
            return;
        }

        if ($element instanceof Initializable) {
            $element->initialize();
        }

        if ($element instanceof HasFakeModel) {
            $element->setFakeModel($this->getModel());
        }
    }

    protected function getNewElements(): Collection
    {
        return $this->cloneElements($this);
    }

    protected function cloneElements(FormElements $element)
    {
        $elements = clone $element->getElements()->map(function ($element) {
            return is_object($element) ? clone $element : $element;
        });

        return $elements->map(function ($element) {
            return $this->emptyElement($element);
        });
    }

    /**
     * @param $element
     *
     * @return Columns|Custom|FormElements
     * @throws Exception
     */
    protected function emptyElement($element)
    {
        $el = is_object($element) ? clone $element : $element;

        if ($el instanceof Columns) {
            $col = new Columns();
            $columns = $el->getElements();
            $columns = (clone $columns)->map(function ($column) {
                return $this->emptyElement($column);
            });
            foreach ($columns as $column) {
                $col->addColumn($column, $column->getWidth());
            }

            $col->setHtmlAttributes($el->getHtmlAttributes());
            $col->initialize();

            return $col;
        }

        if ($el instanceof FormElements) {
            $el->setElements($this->cloneElements($el)->all());
        } else {
            if (! ($el instanceof Custom)) {
                //$el->setDefaultValue(null);
            }

            // Save process: v2
            // if (is_object($el) && $this->needToSetValueSkipped()) {
            //     $el->setValueSkipped(true);
            // }
        }

        // Save process: v2
        // if (is_callable($this->emptyElementCallback)) {
        //     call_user_func($this->emptyElementCallback, $el);
        // }

        /**
         * Write this in your Section if you want to provide model instance directly
         * or use uploadable (like image) fields inside your hasManyLocal element:
         *      ->setInstance($model)
         *
         * You can get model instance inside onEdit() via $this->getModelValue()
         */
        if ($this->getInstance()) {
            $el->setModel($this->getInstance());
        }

        return $el;
    }

    /**
     * @param Model $model
     *
     * @return FormElements|void
     * @throws \Illuminate\Database\Eloquent\ModelNotFoundException
     */
    public function setModel(Model $model)
    {
        parent::setModel($model);

        if ($model->exists) {
            $this->setInstance($model);
            $this->loadFieldValues();
        }
    }

    /**
     * @return Model
     */
    public function getInstance()
    {
        return $this->instance;
    }

    /**
     * @param $instance
     *
     * @return $this
     */
    public function setInstance($instance)
    {
        $this->instance = $instance;

        return $this;
    }

    /**
     * Sets field name property.
     *
     * @param string
     *
     * @return HasManyLocal
     */
    public function setFieldName(string $name): self
    {
        $this->fieldName = $name;

        return $this;
    }

    public function getFieldName(): string
    {
        return $this->fieldName;
    }

    /**
     * @throws Exception
     */
    protected function loadFieldValues()
    {
        $this->fieldValues = $this->getFieldValues();
{'fraction_non_alphanumeric': 0.1265837773830669, 'fraction_numerical': 0.00047365304914150384, 'mean_word_length': 1.9742912484592359, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 113, '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': '5550019', 'n_tokens_mistral': 4730, 'n_tokens_neox': 4620, 'n_words': 964}