AthensFramework/core

View on GitHub
src/admin/Admin.php

Summary

Maintainability
C
1 day
Test Coverage
<?php

namespace Athens\Core\Admin;

use Athens\Core\Etc\StringUtils;
use Athens\Core\FormAction\FormActionBuilder;
use Athens\Core\Section\SectionBuilder;
use Athens\Core\Visitor\VisitorInterface;
use Athens\Core\Etc\ArrayUtils;
use Athens\Core\Field\FieldBuilder;
use Athens\Core\Writable\WritableInterface;
use Athens\Core\Table\TableBuilder;
use Athens\Core\Row\RowBuilder;
use Athens\Core\Row\RowInterface;
use Athens\Core\Form\FormBuilder;
use Athens\Core\FormAction\FormActionInterface;
use Athens\Core\Page\Page;
use Athens\Core\WritableBearer\WritableBearerBuilder;
use Athens\Core\ORMWrapper\ObjectWrapperInterface;
use Athens\Core\ORMWrapper\QueryWrapperInterface;

/**
 * Class ObjectManager
 *
 * @package Athens\Core\Page
 */
class Admin extends Page
{
    const MODE_PAGE = 'page';
    const MODE_TABLE = 'table';
    const MODE_DETAIL = 'detail';
    const MODE_DELETE = 'delete';

    const MODE_FIELD = 'mode';
    const OBJECT_ID_FIELD = 'object_id';
    const QUERY_INDEX_FIELD = 'query_index';

    /** @var QueryWrapperInterface[] */
    protected $queries;

    /**
     * Admin constructor.
     *
     * @param string                  $id
     * @param string                  $type
     * @param string[]                $classes
     * @param array                   $data
     * @param string                  $title
     * @param string                  $baseHref
     * @param VisitorInterface        $initializer
     * @param VisitorInterface        $renderer
     * @param WritableInterface       $pageContents
     * @param QueryWrapperInterface[] $queries
     * @throws \Exception If an invalid object manager mode is provided.
     */
    public function __construct(
        $id,
        $type,
        array $classes,
        array $data,
        $title,
        $baseHref,
        VisitorInterface $initializer,
        VisitorInterface $renderer,
        WritableInterface $pageContents,
        array $queries
    ) {

        /** @var string $mode */
        $mode = $this->getParameter(static::MODE_FIELD, static::MODE_PAGE);

        $this->queries = $queries;

        switch ($mode) {
            case static::MODE_PAGE:
                $writable = $pageContents;
                $type = static::TYPE_MINI_HEADER;
                break;
            case static::MODE_TABLE:
                $sectionBuilder = SectionBuilder::begin()
                    ->setId('admin-tables-container');

                foreach ($this->makeTables() as $table) {
                    $sectionBuilder->addWritable($table);
                }

                $writable = WritableBearerBuilder::begin()
                    ->addWritable($sectionBuilder->build())
                    ->build();

                $type = static::TYPE_MINI_HEADER;
                break;
            case static::MODE_DETAIL:
                $writable = $this->makeDetail();
                $type = static::TYPE_BARE;
                break;
            case static::MODE_DELETE:
                $writable = $this->makeDelete();
                $type = static::TYPE_BARE;
                break;
            default:
                throw new \Exception(
                    "Invalid object manager mode '$mode' provided in URL parameters."
                );
        }

        parent::__construct(
            $id,
            $type,
            $classes,
            $data,
            $title,
            $baseHref,
            $initializer,
            $renderer,
            $writable
        );
    }

    /**
     * @param string $key
     * @param string $default
     * @return string
     */
    protected function getParameter($key, $default = null)
    {
        return ArrayUtils::findOrDefault($key, $_GET, $default);
    }

    /**
     * @return integer|null
     */
    protected function getObjectId()
    {
        /** @var string|null $objectId */
        $objectId = $this->getParameter(static::OBJECT_ID_FIELD);

        return is_numeric($objectId) === true ? (int)$objectId : null;
    }

    /**
     * @return integer|null
     */
    protected function getQueryIndex()
    {
        /** @var string|null $queryIndex */
        $queryIndex = $this->getParameter(static::QUERY_INDEX_FIELD);

        return is_numeric($queryIndex) === true ? (int)$queryIndex : null;
    }

    /**
     * @return QueryWrapperInterface
     */
    protected function getQuery()
    {
        return $this->queries[$this->getQueryIndex()];
    }

    /**
     * Finds an object with the given id in this ObjectManager's query.
     *
     * @param boolean $createOnNoId
     * @return ObjectWrapperInterface
     * @throws \Exception If object can not be found.
     */
    protected function getObjectOr404($createOnNoId = false)
    {
        /** @var integer|null $objectId */
        $objectId = static::getObjectId();

        /** @var ObjectWrapperInterface $object */
        $object = null;

        if ($objectId !== null) {
            $object = $this->getQuery()->findOneByPrimaryKey($objectId);
        } elseif ($createOnNoId === true) {
            $object = $this->getQuery()->createObject();
        }

        if ($object === null) {
            http_response_code(404);
            throw new \Exception('Object not found.');
        }

        return $object;
    }

    /**
     * @param QueryWrapperInterface[]|null $queries
     * @return WritableInterface[]
     */
    protected function makeTables($queries = null)
    {
        /** @var WritableInterface[] $tables */
        $tables = [];

        foreach ($this->queries as $queryIndex => $query) {
            $objects = $query->find();

            /** @var RowInterface[] $rows */
            $rows = [];

            /** @var string $tableName */
            $tableName = StringUtils::slugify($query->getTitleCasedObjectName());

            foreach ($objects as $object) {
                /** @var string $detailurl */
                $detailurl = static::makeUrl(
                    [
                        static::MODE_FIELD => static::MODE_DETAIL,
                        static::QUERY_INDEX_FIELD => $queryIndex,
                        static::OBJECT_ID_FIELD => $object->getPrimaryKey()
                    ]
                );

                $rows[] = RowBuilder::begin()
                    ->addObject($object)
                    ->setOnClick(
                        "
                    athens.multi_panel.loadPanel(1, '$detailurl');
                    athens.multi_panel.openPanel(1);
                    "
                    )
                    ->build();
            }

            /** @var string $adderUrl */
            $adderUrl = static::makeUrl(
                [
                    static::MODE_FIELD => static::MODE_DETAIL,
                    static::QUERY_INDEX_FIELD => $queryIndex,
                ]
            );

            $rows[] = RowBuilder::begin()
                ->addWritable(
                    FieldBuilder::begin()
                        ->setLabel("adder")
                        ->setType(FieldBuilder::TYPE_LITERAL)
                        ->addClass('adder')
                        ->setInitial("+ Add another")
                        ->build(),
                    "adder"
                )
                ->setOnClick(
                    "
                    athens.multi_panel.loadPanel(1, '$adderUrl');
                    athens.multi_panel.openPanel(1);
                "
                )
                ->build();

            $tables[] = SectionBuilder::begin()
                ->setId('object-manager-table-wrapper-' . $tableName)
                ->addLabel(ucwords($tableName))
                ->addWritable(
                    TableBuilder::begin()
                        ->setId('object-manager-table-' . $tableName)
                        ->addRows($rows)
                        ->build()
                )
                ->build();
        }

        return $tables;
    }

    /**
     * @return WritableInterface
     * @throws \Exception If object id not provided, or object not found.
     */
    protected function makeDetail()
    {
        /** @var boolean $idWasProvided */
        $idWasProvided = static::getObjectId() !== null;

        /** @var ObjectWrapperInterface $object */
        $object = $this->getObjectOr404(true);

        /** @var string $className */
        $className = $this->getQuery()->getTitleCasedObjectName();

        /** @var string $tableName */
        $tableName = StringUtils::slugify($className);

        /** @var FormActionInterface $submitAction */
        $submitAction = FormActionBuilder::begin()
            ->setType(FormActionBuilder::TYPE_JAVASCRIPT)
            ->setLabel('Save')
            ->addClass('save')
            ->setTarget("
                athens.ajax.submitForm($(this).closest('form')[0], function(){
                        athens.multi_panel.closePanel(1);
                        athens.ajax_section.loadSection('object-manager-table-$tableName');
                    });
                return false;
            ")
            ->build();

        /** @var string $deleteUrl */
        $deleteUrl = static::makeUrl(
            [
                static::MODE_FIELD => static::MODE_DELETE,
                static::QUERY_INDEX_FIELD => $this->getQueryIndex(),
                static::OBJECT_ID_FIELD => $object->getPrimaryKey()
            ]
        );

        /** @var FormActionInterface $deleteAction */
        $deleteAction = FormActionBuilder::begin()
            ->setType(FormActionBuilder::TYPE_JAVASCRIPT)
            ->setLabel('Delete')
            ->setTarget("
                if (confirm('Are you sure you want to delete this object?')) {
                    athens.alert.makeAlert('Deleting object.', 'info');
                    athens.ajax.post(
                        '$deleteUrl',
                        {
                          csrf_token: CSRFTOKEN,
                        },
                        function() {},
                        function() {
                            athens.alert.makeAlert('Object deleted', 'success');
                            athens.multi_panel.closePanel(1);
                            athens.ajax_section.loadSection('object-manager-table-$tableName');
                        }
                    );
                }
                return false;
            ")
            ->build();

        $formBuilder = FormBuilder::begin()
            ->setId('object-manager-detail-form')
            ->addObject($object)
            ->removeWritable($object->getPascalCasedObjectName() . '.Id')
            ->addAction($submitAction);

        if ($idWasProvided === true) {
            $formBuilder->addAction($deleteAction);
        }

        $sectionBuilder = SectionBuilder::begin()
            ->setId('object-manager-detail-form-wrapper')
            ->addLabel($className)
            ->addWritable(
                $formBuilder->build()
            );

        return $sectionBuilder->build();
    }

    /**
     * @return WritableInterface
     */
    protected function makeDelete()
    {
        $this->getObjectOr404()->delete();

        return SectionBuilder::begin()
            ->addContent('Object deleted')
            ->build();
    }

    /**
     * @param string[] $data
     * @param string   $location
     * @return string
     */
    protected static function makeUrl(array $data, $location = null)
    {
        $location = $location === null ? $_SERVER['REQUEST_URI'] : $location;

        $args = http_build_query($data);

        return strpos($location, '?') === false ? "$location?$args" : "$location&$args";
    }
}