HEX
Server: Microsoft-IIS/8.5
System: Windows NT YDAWBH120 6.3 build 9600 (Windows Server 2012 R2 Standard Edition) AMD64
User: tentjecom_web (0)
PHP: 7.4.14
Disabled: NONE
Upload Files
File: D:/HostingSpaces/Neopoints/momsecurity.be/app/Komma/Dynamic/ComponentType/ComponentTypeBuilder.php
<?php


namespace App\Komma\Dynamic\ComponentType;

use App\Helpers\KommaHelpers;
use App\Komma\Dynamic\Component\Component;
use App\Komma\Dynamic\Component\ComponentableInterface;
use App\Komma\Dynamic\Component\ComponentableTrait;
use App\Komma\Dynamic\Componentables\ComponentableService;
use App\Komma\Dynamic\Componentables\ComponentableType;
use App\Komma\Dynamic\ComponentType\SaveState\SaveStateBuilder;
use App\Komma\Kms\Core\Attributes\Attribute;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;

/**
 * Class ComponentTypeBuilder
 *
 * Can build DynamicGroupTypes that act as templates for instances of ComponentType.
 * It also saves the component to the database because it may be linked to other models.
 *
 * @package App\Komma\Dynamic\ComponentType
 */
class ComponentTypeBuilder extends AbstractComponentTypeBuilder
{
    /** @var string */
    public const DEFAULT_ICON = '/img/kms/dynamic/default-group-type.svg';

    /** @var Attribute[] */
    private $attributes = [];

    private $componentablesToBuildAttributes = []; //Contains arrays containing attributes and values for componentables to build

    public function __construct()
    {
        $this->componentType = new ComponentType();
        $this->componentType->icon = self::DEFAULT_ICON;
    }

    /**
     * @param Attribute $attribute
     * @return ComponentTypeBuilder
     */
    public function addAttribute(Attribute $attribute): AbstractComponentTypeBuilder {
        $this->attributes[] = $attribute;

        return $this;
    }

    /**
     * @return ComponentTypeInterface
     */
    public function build(): ComponentTypeInterface
    {
        $this->validate();

        $saveStateBuilder = (new SaveStateBuilder())->setVersion(ComponentType::SAVESTATE_VERSION);
        foreach($this->attributes as $attribute) {
            $saveStateBuilder->addAttributeInstance($attribute);
        }
        $saveState = $saveStateBuilder->build();

        $this->componentType->save_state_instance = $saveState;

        $this->componentType->save();

        foreach($this->componentablesToBuildAttributes as $componentableDataToBuild)
        {
            $this->componentType->componentableTypes()->save((new ComponentableType($componentableDataToBuild)));
        }

        return $this->componentType;
    }


    /**
     * @return ComponentTypeInterface | boolean
     */
    public function update($name)
    {
        if($name == null) return false;

        $this->componentType = ComponentType::where('name',$name)->first();

        if(empty($this->componentType)) throw new \InvalidArgumentException('A component with name "'.$name.'" was not found. Did you spell it correctly?');

        $this->validate(true);

        $saveStateBuilder = (new SaveStateBuilder())->setVersion(ComponentType::SAVESTATE_VERSION);
        foreach($this->attributes as $attribute) {
            $saveStateBuilder->addAttributeInstance($attribute);
        }
        $saveState = $saveStateBuilder->build();

        $this->componentType->save_state_instance = $saveState;

        $this->componentType->save();

        foreach($this->componentablesToBuildAttributes as $componentableDataToBuild)
        {
            $this->componentType->componentableTypes()->save((new ComponentableType($componentableDataToBuild)));
        }

        return $this->componentType;
    }

    /**
     * @param string $name
     * @return AbstractComponentTypeBuilder
     */
    public function setName(string $name): AbstractComponentTypeBuilder
    {
        $this->componentType->name = $name;

        return $this;
    }

    /**
     * @param string $icon
     * @return AbstractComponentTypeBuilder
     */
    public function setIcon(string $icon): AbstractComponentTypeBuilder
    {
        $this->componentType->icon = $icon;

        return $this;
    }

    /**
     * @param string $componentable
     * @param string $modelCollectionProvider an @ delimited string that defines a class and a method that returns a collection of models that can be linked
     * @return ComponentTypeBuilder
     * @throws \ReflectionException
     */
    public function linkableToModel(string $componentable, string $modelCollectionProvider)
    {
        if(!is_a($componentable, ComponentableInterface::class, true)) throw new \InvalidArgumentException('The given model "'.$componentable.'" must be an implementation of the "'.ComponentableInterface::class.'" interface');
        $parts = explode('@', $modelCollectionProvider);
        if(!count($parts) == 2) throw new \InvalidArgumentException('The provider parameter must exactly have one @ sign.');
        /** @var ComponentableInterface $componentable */

        //Lets make sure that the linked models have Polymorphic relations to each other
        ComponentableService::getAndValidateComponentableMethodNameOnComponentClassUsingComponentable($componentable);

        //   Validate that Components is a method on the Componentable class (Users for example) that returns the correct relation
        ComponentableService::getAndValidateComponentsMethodNameOnComponentable($componentable);

        //Build an array of attributes and values that represent represent a componentable (linkable model) for the build method to use when building this component type.
        $this->componentablesToBuildAttributes[] = [
            'componentable_type' => $componentable,
            'model_collection_provider' => $modelCollectionProvider
        ];

        return $this;
    }



    /**
     * Validate the completeness of the ComponentType
     */
    private function validate($update = false): bool
    {
        if( ! $update)
        {
            if(ComponentType::where('name', '=', $this->componentType->name)->count() > 0)
                throw new \InvalidArgumentException('A dynamicGroupType with name "'.$this->componentType->name.'" already exists.');
        }

        if ($this->componentType->name == '' || $this->componentType->icon == '')
            throw new \RuntimeException('The dynamicGroupType must have a name and an icon to function properly. Please call the setName and setIcon methods on this builder to do that');

        return true;
    }
}