2

Developing plugin for Craft 3, I want to add extra property to Assets (data being pulled from other table)

I am able to pull in the data by extending element query:

Event::on(
            ElementQuery::class,
            ElementQuery::EVENT_AFTER_PREPARE,
            function(CancelableEvent $e) {
                if ($e->sender->elementType == 'craft\\elements\\Asset')
                {
                    $e->sender->query->addSelect('linkstats.downloads');

                    $subQuery = (new Query())
                        ->select('assetId, SUM(downloads) AS downloads')
                        ->from('{{%my_plugin_table}}')
                        ->groupBy('assetId');

                    $e->sender->query->leftJoin(
                        ['linkstats' => $subQuery], 'assets.id = linkstats.assetId'
                    );
                }
            }
        );

However when trying to display the asset I get error:

Setting unknown property: craft\elements\Asset::downloads

Question, how do I register this new property/attribute for Assets? I cannot find any event to do that, is it possible at all?

2 Answers 2

3

Another approach is to use the following event to attach a behavior

Event::on(Asset::class, Asset::EVENT_DEFINE_BEHAVIORS, 
function(DefineBehaviorsEvent $event) {
    $event->behaviors[] = MyBehavior::class;
});

The behavior could look like

class MyBehavior extends Behavior { 
    public $downloads; 
}

This way you won't receive an exception and can access your property via

$asset = Assets::find()->all();
$asset->downloads;

You can as well manipulate the value of downloads in the Behaviors init function in order to return the file or something like this

0

You can use the asArray() function in order to gain the raw query result and populate the entry on your own.

Just take a look at the ElementQuery->populate() function, copy it to you own service and attach your custom Behavior you can see how this works here

class MyBehavior extends Behavior { 

    public $prop1; 
    private $_prop2;

    public function getProp2() {
        return $this->_prop2; 
    } 

    public function setProp2($value) { 
         $this->_prop2 = $value;
    }
 }

Just include all values for the element in your custom behavior.

The key is to change this piece of code from

$element = new $class($row);

To

$element = new $class();
$element->attachBehavior('myBehavior1', new MyBehavior);
Craft::configure($element, $row);

In your custom service.

2
  • Thanks, but it's not what I need. I don't want to create my own copy of Assets service/variable, instead I want to add a property for all standard calls (to make it also available in CP) Commented Apr 27, 2018 at 4:23
  • That's not possible because you'll always receive the exception that way. Another possibility is to load the data in your behavior Commented Apr 27, 2018 at 4:27

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.