Answers.Body: <p>Another approach is to use the following event to attach a behavior</p>
  
  <pre><code>Event::on(Asset::class, Asset::EVENT_DEFINE_BEHAVIORS, 
  function(DefineBehaviorsEvent $event) {
      $event-&gt;behaviors[] = MyBehavior::class;
  });
  </code></pre>
  
  <h3>The behavior could look like</h3>
  
  <pre><code>class MyBehavior extends Behavior { 
      public $downloads; 
  }
  </code></pre>
  
  <p>This way you won't receive an exception and can access your property via</p>
  
  <pre><code>$asset = Assets::find()-&gt;all();
  $asset-&gt;downloads;
  </code></pre>
  
  <p>You can as well manipulate the value of <code>downloads</code> in the <code>Behaviors</code> init function in order to return the file or something like this</p>
  
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2018-05-04T13:58:04.017Z
Answers.LastActivityDate: 2018-05-04T13:58:04.017Z
Answers.UserDisplayName: Robin Schambach
Answers.Body: <p>You can use the <code>asArray()</code> function in order to gain the raw query result and populate the entry on your own.</p>
  
  <p>Just take a look at the <code>ElementQuery-&gt;populate()</code> function, copy it to you own service and attach your custom <code>Behavior</code> you can see how this works <a href="https://www.yiiframework.com/doc/guide/2.0/en/concept-behaviors#attaching-behaviors" rel="nofollow noreferrer">here</a> </p>
  
  <pre><code>class MyBehavior extends Behavior { 
  
      public $prop1; 
      private $_prop2;
  
      public function getProp2() {
          return $this-&gt;_prop2; 
      } 
  
      public function setProp2($value) { 
           $this-&gt;_prop2 = $value;
      }
   }
  </code></pre>
  
  <p>Just include all values for the element in your custom behavior. </p>
  
  <p>The key is to change <a href="https://github.com/craftcms/cms/blob/develop/src/elements/db/ElementQuery.php#L2055" rel="nofollow noreferrer">this</a> piece of code from </p>
  
  <pre><code>$element = new $class($row);
  </code></pre>
  
  <p>To </p>
  
  <pre><code>$element = new $class();
  $element-&gt;attachBehavior('myBehavior1', new MyBehavior);
  Craft::configure($element, $row);
  </code></pre>
  
  <p>In your custom service. </p>
  
Answers.ContentLicense: CC BY-SA 3.0
Answers.CreationDate: 2018-04-27T04:23:20.750Z
Answers.Text: 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)
Answers.UserDisplayName: Yuri Salimovskiy
Answers.ContentLicense: CC BY-SA 3.0
Answers.CreationDate: 2018-04-27T04:27:59.280Z
Answers.Text: That's not possible because you'll always receive the exception that way. Another possibility is to load the data in your behavior
Answers.UserDisplayName: Robin Schambach
Answers.ContentLicense: CC BY-SA 3.0
Answers.CreationDate: 2018-04-26T20:13:33.313Z
Answers.LastActivityDate: 2018-04-26T20:13:33.313Z
Answers.UserDisplayName: Robin Schambach
Body: <p>Developing plugin for Craft 3, I want to add extra property to Assets (data being pulled from other table)</p>
  
  <p>I am able to pull in the data by extending element query:</p>
  
  <pre><code>Event::on(
              ElementQuery::class,
              ElementQuery::EVENT_AFTER_PREPARE,
              function(CancelableEvent $e) {
                  if ($e-&gt;sender-&gt;elementType == 'craft\\elements\\Asset')
                  {
                      $e-&gt;sender-&gt;query-&gt;addSelect('linkstats.downloads');
  
                      $subQuery = (new Query())
                          -&gt;select('assetId, SUM(downloads) AS downloads')
                          -&gt;from('{{%my_plugin_table}}')
                          -&gt;groupBy('assetId');
  
                      $e-&gt;sender-&gt;query-&gt;leftJoin(
                          ['linkstats' =&gt; $subQuery], 'assets.id = linkstats.assetId'
                      );
                  }
              }
          );
  </code></pre>
  
  <p>However when trying to display the asset I get error:</p>
  
  <blockquote>
    <p>Setting unknown property: craft\elements\Asset::downloads</p>
  </blockquote>
  
  <p>Question, how do I register this new property/attribute for Assets? I cannot find any event to do that, is it possible at all?</p>
  
Tags: <plugin-development><craft3><attribute><element>
Title: Add custom attribute to standard element from plugin
ThreadText: # Add custom attribute to standard element from plugin
  
  (Asked by: username_0 on 2018-04-26)
  
  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?
  
  **Tags:** plugin-development, craft3, attribute, element
  
  
  ---
  
  ## 2 answers
  
  ### Answer by username_1 on 2018-05-04. Score: 3 | Accepted answer
  
  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
  
  
  ---
  
  ### Answer by username_1 on 2018-04-26. Score: 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](https://www.yiiframework.com/doc/guide/2.0/en/concept-behaviors#attaching-behaviors)
  
  ```
  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](https://github.com/craftcms/cms/blob/develop/src/elements/db/ElementQuery.php#L2055) 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.
  
  > **Comments:**
  > **username_0**: 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)  
  > **username_1**: That's not possible because you'll always receive the exception that way. Another possibility is to load the data in your behavior  
  
  ---
  
  