Skip to content

Instantly share code, notes, and snippets.

@timkelty
Last active November 14, 2019 13:46
Show Gist options
  • Select an option

  • Save timkelty/93de4332e535bd65d09daece358e3332 to your computer and use it in GitHub Desktop.

Select an option

Save timkelty/93de4332e535bd65d09daece358e3332 to your computer and use it in GitHub Desktop.
Craft CMS: Adding behaviors by section, enforcing interfaces + traits
<?php
namespace modules\appmodule\behaviors;
use Craft;
use craft\base\Element;
use craft\base\ElementInterface;
use craft\db\Table;
use craft\elements\db\ElementQuery;
use craft\elements\db\EntryQuery;
use craft\elements\Entry;
use craft\elements\User;
use craft\helpers\StringHelper;
use craft\helpers\UrlHelper;
use Tightenco\Collect\Support\Collection;
use verbb\supertable\elements\db\SuperTableBlockQuery;
use yii\base\Behavior;
use yii\helpers\Inflector;
class Gear extends Behavior implements ReviewableInterface
{
use ReviewableTrait;
public function getReviews(): EntryQuery
{
return Entry::find()
->section('reviews')
->relatedTo([
'targetElement' => $this->owner,
'field' => 'product',
]);
}
public function getReviewSubmissionUrl(): string
{
return UrlHelper::siteUrl('gear/new-review', ['product' => $this->owner->id]);
}
public function getReviewsUrl(): string
{
return UrlHelper::siteUrl(implode('/', [$this->owner->uri, 'reviews']));
}
}
<?php
namespace modules\appmodule\behaviors;
use Craft;
use craft\elements\db\EntryQuery;
interface ReviewableInterface
{
public function getReviews(): EntryQuery;
public function getReviewCount(): int;
public function getReviewAverage(): float;
public function getReviewSubmissionUrl(): string;
public function getReviewsUrl(): string;
}
<?php
namespace modules\appmodule\behaviors;
use Craft;
use Tightenco\Collect\Support\Collection;
use yii\base\Behavior;
trait ReviewableTrait
{
public function getReviewCount(): int
{
return $this->owner->getReviews()->count();
}
public function getReviewAverage(): float
{
return round(Collection::make($this->owner->getReviews()->all())->map(function ($item) {
return intval($item->reviewRating);
})->avg(), 1);
}
}
<?php
namespace modules\appmodule\behaviors;
use Craft;
use craft\base\Element;
use craft\base\ElementInterface;
use craft\db\Table;
use craft\elements\db\EntryQuery;
use craft\elements\Entry;
use craft\elements\User;
use Tightenco\Collect\Support\Collection;
use yii\base\Behavior;
class Trip extends Behavior implements ReviewableInterface
{
use ReviewableTrait;
public function getReviewSubmissionUrl(): string
{
return UrlHelper::siteUrl('paddle/trips/new');
}
public function getReviewsUrl(): string
{
return UrlHelper::siteUrl(implode('/', [$this->owner->uri, 'reviews']));
}
public function getReviews(): EntryQuery
{
return Entry::find()
->section('tripReviews')
->relatedTo([
'targetElement' => $this->owner,
'field' => 'trip',
]);
}
}
<?php
namespace modules\appmodule;
use Craft;
use craft\elements\Entry;
use craft\events\DefineBehaviorsEvent;
use craft\events\ModelEvent;
use Tightenco\Collect\Support\Collection;
use yii\base\Event;
class Module extends \yii\base\Module
{
const SECTION_BEHAVIORS = [
'products' => [
\modules\appmodule\behaviors\Gear::class,
],
'trips' => [
\modules\appmodule\behaviors\Trip::class
],
];
public function init()
{
parent::init();
// Yii requires an alias be set for controllerNamespace
Craft::setAlias('@modules/appmodule', $this->getBasePath());
$this->controllerNamespace = Craft::$app->getRequest()->getIsConsoleRequest()
? 'modules\appmodule\console\controllers'
: 'modules\appmodule\controllers';
$this->setComponents([
'inflector' => \yii\helpers\Inflector::class,
'string' => \craft\helpers\StringHelper::class,
]);
Event::on(
Entry::class,
Entry::EVENT_DEFINE_BEHAVIORS,
function (DefineBehaviorsEvent $event) {
// Avoid exceptions for unpopulated entry…not 💯why this happens in CP
// https://craftcms.stackexchange.com/questions/32992/conditionally-attach-behaviors-to-craft-elements-entry-by-section
if (!$event->sender->id) {
return;
}
$event->behaviors = Collection::make(self::SECTION_BEHAVIORS)
->filter(function ($behaviors, $sectionHandle) use ($event) {
return $event->sender->section->handle === $sectionHandle;
})
->prepend($event->behaviors)
->flatten()
->all();
}
);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment