Creating a Attribute Category

Improvements?

Let us know by posting here.

Adding Attributes to Custom Objects

To enhance custom objects with attribute support in Concrete, create attribute keys and custom attribute types. For objects needing attributes, complete an attribute category, Doctrine ORM entities, and implement getAttribute() and setAttribute() methods.

Package Creation

Develop your custom attribute category within a package for straightforward installation and management. For instance, a "Calendar" package at packages/calendar can include a "MyCal\Entity\Calendar\Event" custom object. Detailed package documentation can be found here.

Entity Setup

Create entities for event Key and Value, Concrete\Package\Calendar\Entity\Attribute\Key\EventKey and Concrete\Package\Calendar\Entity\Attribute\Value\EventValue, extending Concrete\Core\Entity\Attribute\Key\Key and Concrete\Core\Entity\Attribute\Value\AbstractValue respectively. Place these in:

  • packages/calendar/src/Concrete/Entity/Attribute/Key/EventKey
  • packages/calendar/src/Concrete/Entity/Attribute/Value/EventValue

Here are the example classes:

// EventKey example
namespace Concrete\Package\Calendar\Entity\Attribute\Key;
use Concrete\Core\Entity\Attribute\Key\Key;
use Doctrine\ORM\Mapping as ORM;

/**
 * @ORM\Entity
 * @ORM\Table(name="CalendarEventAttributeKeys")
 */
class EventKey extends Key {
    public function getAttributeKeyCategoryHandle() {
        return 'event';
    }
}

// EventValue example
namespace Concrete\Package\Calendar\Entity\Attribute\Value;
use Concrete\Core\Entity\Attribute\Value\AbstractValue;
use Doctrine\ORM\Mapping as ORM;

/**
 * @ORM\Entity
 * @ORM\Table(name="CalendarEventAttributeValues")
 */
class EventValue extends AbstractValue {
    /**
     * @ORM\ManyToOne(targetEntity="\MyCal\Entity\Calendar\Event")
     * @ORM\JoinColumn(name="eventID", referencedColumnName="eventID")
     */
    protected $event;

    public function getEvent() {
        return $this->event;
    }

    public function setEvent($event) {
        $this->event = $event;
    }
}

Category Controller Class Creation

Develop Concrete\Package\Calendar\Attribute\Category\EventCategory in packages/calendar/src/Concrete/Attribute/Category/EventCategory, implementing Concrete\Core\Attribute\Category\CategoryInterface. Example:

namespace Concrete\Package\Calendar\Attribute\Category;
use Concrete\Core\Entity\Attribute\Key\Key;
use Concrete\Package\Calendar\Entity\Attribute\Key\EventKey;
use Concrete\Package\Calendar\Entity\Attribute\Value\EventValue;

class EventCategory extends AbstractStandardCategory {
    // Implementation details...
}

Attribute Category Registration

In your package's on_start() method, register the attribute category:

public function on_start() {
    $this->app['manager/attribute/category']->extend('event', 
    function($app) {
        return $app->make('Concrete\Package\Calendar\Attribute\Category\EventCategory');
    });
}

Setting up Dashboard Pages

Configure dashboard pages for managing event attribute keys at /dashboard/calendar/attributes. Create a controller at Concrete\Package\Calendar\Controller\SinglePage\Dashboard\Calendar\Attributes and extend DashboardAttributesPageController. Implement necessary methods for attribute management. Example contents for packages/calendar/single_pages/dashboard/calendar/attributes.php:

<?php defined('C5_EXECUTE') or die("Access Denied.");?>
<?php
$attributeView->render();
?>

By extending DashboardAttributesPageController, the controller handles the functionality, simplifying view layer creation.

Adding Attribute Support to Custom Object

To enable attribute support in MyCal\Entity\Calendar\Event, add:

use \Concrete\Core\Attribute\ObjectTrait;

and implement the required methods:

public function getObjectAttributeCategory();
public function getAttributeValueObject($ak, $createIfNotExists = false);

Example implementation:

use Core;
use Concrete\Package\Calendar\Entity\Attribute\Key\EventKey;
use Concrete\Package\Calendar\Entity\Attribute\Value\EventValue;

public function getObjectAttributeCategory()
{
    return \Core::make('\Concrete\Package\Calendar\Attribute\Category\EventCategory');
}

public function getAttributeValueObject($ak, $createIfNotExists = false)
{
    // ... [implementation details]
}

This allows setAttribute() and getAttribute() to function on the custom event object.

Package and Dashboard Page Installation

Install the attribute category and Dashboard pages using Concrete's content importer in the install() method:

public function install()
{
    $this->on_start();
    $this->installContentFile('content.xml');
}

Include these XML tags in content.xml for dashboard pages and attribute category:

<?xml version="1.0" encoding="UTF-8"?>
<concrete5-cif version="1.0">
    <attributecategories>
        <category handle="event" allow-sets="1" package="calendar"/>
    </attributecategories>
    <singlepages>
        <!-- Dashboard pages XML data -->
    </singlepages>
</concrete5-cif>

Conclusion

This setup enables a fully functional attribute key category for the custom object with dashboard interfaces.

Enhancing Attribute Category

Add extra fields to attribute categories like Concrete\Core\Entity\Attribute\Key\UserKey. For instance, to add 'Public Display' options in user attributes:

  1. Key Entity with Extra Fields: Add additional fields in the key entity.

    class UserKey extends Key
    {
       // ... [fields and methods]
    }
    
  2. Custom Category Element: Add a custom form in concrete/elements/attribute/categories/user.php:

    // ... [form setup code]
    
  3. Save Additional Settings: Implement saving logic in Concrete\Core\Attribute\Category\UserCategory:

    protected function saveFromRequest(Key $key, Request $request)
    {
       // ... [save logic]
    }
    
    public function addFromRequest(Type $type, Request $request)
    {
       // ... [add logic]
    }
    
    public function updateFromRequest(Key $key, Request $request)
    {
       // ... [update logic]
    }
    

Installing Category via PHP

To install through PHP:

  1. Check if Category Exists:

    use Concrete\Core\Attribute\Key\Category;
    $category = Category::getByHandle('event');
    
  2. Create if Necessary:

    if (!is_object($category)) {
       $category = Category::add('event', false, $pkg);
    }