acf-builder icon indicating copy to clipboard operation
acf-builder copied to clipboard

Instantiation in GroupBuilder constructor

Open MMSs opened this issue 5 years ago • 0 comments

https://github.com/StoutLogic/acf-builder/blob/68e3705505bc85b2d75e8e8d7fbb31181004b4cb/src/GroupBuilder.php#L25

In the mentioned line above, instantiation of a new FieldsBuilder in the GroupBuilder constructor is made.

The problem with this implementation is that it doesn't allow for dependency injection.

The reason dependency injection is needed here is in the case of extending FieldsBuilder.

When I create a new class extending FieldsBuilder lets call it FieldsBuilderChild, calling addRepeater() on FieldsBuilderChild, would make the created repeater reference the parent FieldsBuilder as the parent context, in which there were no repeater created, so when eventually endRepeater() function is called, the function would not exist.

Here's a complete example:

use StoutLogic\AcfBuilder\FieldsBuilder;

class FieldsBuilderChild extends FieldsBuilder 
{
    private $titleField;
    
    public function addTitleField() 
    {
        $this->titleField = $this->addText('title');
    }
}

now when building fields using FieldsBuilderChild

$fields = new FieldsBuilderChild();
$fields->addRepeater('Titles Repeater')
$fields->addTitleField();
$fields->endRepeater();

the following error would be thrown

Fatal error: Uncaught Exception: No such function: endRepeater in .../vendor/stoutlogic/acf-builder/src/ParentDelegationBuilder.php on line 69

For now, to fix this error in my application, I extended both GroupBiulder and RepeaterBuilder, overriding parent context setting, and overridden both addGroup() and addRepeater functions in my child FieldsBuilderChild as follows:

-- GroupBuilder

<?php

namespace Fields;

use StoutLogic\AcfBuilder\GroupBuilder as BaseGroupBuilder;

class GroupBuilder extends BaseGroupBuilder
{
    public function __construct($name, FieldsBuilder $builder, $type = 'group', $config = [])
    {
        parent::__construct($name, $type, $config);
        $this->fieldsBuilder = $builder;
        $this->fieldsBuilder->setParentContext($this);
    }
}

-- RepeaterBuilder

<?php

namespace Fields;

use StoutLogic\AcfBuilder\RepeaterBuilder as BaseRepeaterBuilder;

class RepeaterBuilder extends BaseRepeaterBuilder
{
    public function __construct($name, FieldsBuilder $builder, $type = 'group', $config = [])
    {
        parent::__construct($name, $type, $config);
        $this->fieldsBuilder = $builder;
        $this->fieldsBuilder->setParentContext($this);
    }
}

-- FieldsBuilder

<?php

namespace Fields;

use StoutLogic\AcfBuilder\FieldsBuilder as BaseFieldsBuilder;

class FieldsBuilder extends BaseFieldsBuilder
{
    private $titleField;
    
    public function addGroup($name, array $args = [])
    {
        // overriding the parent addGroup to use the custom GroupBuilder
        return $this->initializeField(new GroupBuilder($name, new self('group'), 'group', $args));
    }

    public function addRepeater($name, array $args = [])
    {
        // overriding the parent addRepeater to use the custom RepeaterBuilder
        return $this->initializeField(new RepeaterBuilder($name, new self('repeater'), 'repeater', $args));
    }

    public function addTitleField() 
    {
        $this->titleField = $this->addText('title');
    }
}

Now the fatal error is no longer thrown, and fields are built correctly.

So, although this solution worked for me, but I think it's rather be implemented in the FieldsBuilder, and if this proposed solution is fine, I could add it and create a pull request.

MMSs avatar Sep 08 '19 13:09 MMSs