krafthaus/bauhaus

View on GitHub
src/KraftHaus/Bauhaus/Builder/FormBuilder.php

Summary

Maintainability
C
1 day
Test Coverage
<?php

namespace KraftHaus\Bauhaus\Builder;

/**
 * This file is part of the KraftHaus Bauhaus package.
 *
 * (c) KraftHaus <hello@krafthaus.nl>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

use Closure;
use Illuminate\Support\Facades\Config;
use Illuminate\Support\Facades\Validator;
use KraftHaus\Bauhaus\Result\FormResult;
use KraftHaus\Bauhaus\Field\BaseField;
use KraftHaus\Bauhaus\Util\Value;

/**
 * Class ListBuilder
 * @package KraftHaus\Bauhaus\Builder
 */
class FormBuilder extends BaseBuilder
{

    const CONTEXT_CREATE = 'create';
    const CONTEXT_EDIT = 'edit';

    /**
     * Holds the form result.
     * @var array
     */
    protected $result = [];

    /**
     * Holds the record identifier(id).
     * @var int
     */
    protected $identifier;

    /**
     * Set the form identifier.
     *
     * @param  int $identifier
     *
     * @access public
     * @return FormBuilder
     */
    public function setIdentifier($identifier)
    {
        $this->identifier = $identifier;
        return $this;
    }

    /**
     * Get the form identifier.
     *
     * @access public
     * @return int
     */
    public function getIdentifier()
    {
        return $this->identifier;
    }

    /**
     * Set the form context.
     *
     * @param  FormBuilder $context
     *
     * @access public
     * @return FormBuilder
     */
    public function setContext($context)
    {
        $this->context = $context;
        return $this;
    }

    /**
     * Get the form context.
     *
     * @access public
     * @return mixed
     */
    public function getContext()
    {
        return $this->context;
    }

    /**
     * Build the list data.
     *
     * @access public
     * @return mixed|void
     */
    public function build()
    {
        $formMapper = $this->getMapper();
        $model      = $this->getModel();
        $primaryKey = (new $model)->getKeyName();

        /**
         * Empty form
         */
        $result = new FormResult();
        if ($this->getIdentifier() === null) {
            foreach ($formMapper->getFields() as $field) {
                $clone = clone $field;
                $name  = $clone->getName();

                // Is this a multiple field?
                if ($clone->isMultiple()) {
                    $clone->setValue(['']);
                }

                $clone->setContext(BaseField::CONTEXT_FORM);
                $result->addField($name, $clone);
            }

            $this->setResult($result);
            return;
        }

        $items = $model::with([]);

        $items->where($primaryKey, $this->getIdentifier());
        $item = $items->first();

        // modifyModelItem hook
        if (method_exists($this->getMapper()->getAdmin(), 'modifyModelItem')) {
            $item = $this->getMapper()->getAdmin()->modifyModelItem($item);
        }

        $result = new FormResult;
        $result->setIdentifier($item->{$primaryKey});

        foreach ($formMapper->getFields() as $field) {
            $clone = clone $field;
            $name  = $clone->getName();
            $value = $item->{$name};

            if ($clone->hasBefore()) {
                $before = $clone->getBefore();

                if ($before instanceof Closure) {
                    $value = $before($value);
                } else {
                    $value = $before;
                }
            }

            // Is this a multiple field?
            if ($clone->isMultiple()) {
                $value = Value::decode(Config::get('bauhaus::admin.multiple-serializer'), $value);
            }

            $clone
                ->setContext(BaseField::CONTEXT_FORM)
                ->setValue($value);

            $result->addField($name, $clone);
        }

        $this->setResult($result);
    }

    /**
     * Sets the form result.
     *
     * @param  array $result
     *
     * @access public
     * @return FormBuilder
     */
    public function setResult(FormResult $result)
    {
        $this->result = $result;
        return $this;
    }

    /**
     * Returns the form result.
     *
     * @access public
     * @return array
     */
    public function getResult()
    {
        return $this->result;
    }

    /**
     * Create a new model from input.
     * 
     * @param  Input $input
     *
     * @access public
     * @return FormBuilder
     */
    public function create($input)
    {
        $mapper = $this->getMapper();
        $admin  = $mapper->getAdmin();

        $model      = $this->getModel();
        $primaryKey = (new $model)->getKeyName();

        $this->setInput($input);

        // Field pre update
        foreach ($mapper->getFields() as $field) {
            $field->preUpdate();
            $input = $this->getInput();

            // Is this a multiple field?
            if ($field->isMultiple()) {
                $value = Value::encode(Config::get('bauhaus::admin.multiple-serializer'), $input[$field->getName()]);
                $this->setInputVariable($field->getName(), $value);
            }

            if ($field->hasSaving()) {
                $saving = $field->getSaving();
                $this->setInputVariable($field->getName(), $saving($input[$field->getName()]));
            }
        }

        // Model before create hook
        if (method_exists($admin, 'beforeCreate')) {
            $admin->beforeCreate($input);
        }

        // Validate
        if (property_exists($model, 'rules')) {
            $validator = Validator::make($this->getInput(), $model::$rules);
            if ($validator->fails()) {
                return $validator;
            }
        }

        // Model create hook
        if (method_exists($admin, 'create')) {
            $model = $admin->create($this->getInput());
        } else {
            $model = $model::create($this->getInput());
        }

        // Set the primary id from the `new` model
        $this->setIdentifier($model->{$primaryKey});

        // Field post update
        foreach ($mapper->getFields() as $field) {
            $field->postUpdate($this->getInput());
        }

        // Model after create hook
        if (method_exists($admin, 'afterCreate')) {
            $result = $admin->afterCreate($this->getInput());

            if ($result instanceof \Illuminate\Http\RedirectResponse) {
                $result->send();
            }
        }

        return $this;
    }

    /**
     * Update a model from input.
     * 
     * @param  Input $input
     *
     * @access public
     * @return FormBuilder
     */
    public function update($input)
    {
        $mapper = $this->getMapper();
        $admin  = $mapper->getAdmin();

        $model = $this->getModel();
        $this->setInput($input);

        // Field pre update
        foreach ($this->getMapper()->getFields() as $field) {
            $field->preUpdate();

            // Is this a multiple field?
            if ($field->isMultiple()) {
                $value = Value::encode(Config::get('bauhaus::admin.multiple-serializer'), $input[$field->getName()]);
                $this->setInputVariable($field->getName(), $value);
            }

            if ($field->hasSaving()) {
                $saving = $field->getSaving();
                $this->setInputVariable($field->getName(), $saving($input[$field->getName()]));
            }
        }

        // Model before update hook
        if (method_exists($admin, 'beforeUpdate')) {
            $admin->beforeUpdate($input);
        }

        // Validate
        if (property_exists($model, 'rules')) {
            $validator = Validator::make($this->getInput(), $model::$rules);
            if ($validator->fails()) {
                return $validator;
            }
        }

        // Model update hook
        if (method_exists($this->getMapper()->getAdmin(), 'update')) {
            $this->getMapper()->getAdmin()->update($this->getInput());
        } else {
            $model::find($this->getIdentifier())
                ->update($this->getInput());
        }

        // Field post update
        foreach ($this->getMapper()->getFields() as $field) {
            $field->postUpdate($this->getInput());
        }

        // Model after update hook
        if (method_exists($admin, 'afterCreate')) {
            $result = $admin->afterUpdate($this->getInput());

            if ($result instanceof \Illuminate\Http\RedirectResponse) {
                $result->send();
            }
        }

        return $this;
    }

    /**
     * Destroy a specific item.
     *
     * @access public
     * @return FormBuilder
     */
    public function destroy()
    {
        $mapper = $this->getMapper();
        $admin  = $mapper->getAdmin();

        $model = $this->getModel();
        $model = $model::find($this->getIdentifier());

        // Model before delete hook
        if (method_exists($admin, 'beforeDelete')) {
            $admin->beforeDelete($model);
        }

        // Model delete hook
        if (method_exists($admin, 'deleting')) {
            $admin->deleting($model);
        } else {
            $model->delete();
        }

        // Model after delete hook
        if (method_exists($admin, 'afterDelete')) {
            $result = $admin->afterDelete($model);

            if ($result instanceof \Illuminate\Http\RedirectResponse) {
                $result->send();
            }
        }

        return $this;
    }

}