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;
}
}