Answers.Body: <p>It doesn't <em>really</em> matter as long as you make sure to type-hint correctly relative to the current namespace and/or use the fully qualified class name. However, it's best to follow the established conventions of the core or in this case, the plugin you're building on. The Webhooks plugin puts all the default filters in the <a href="https://github.com/craftcms/webhooks/tree/develop/src/filters" rel="nofollow noreferrer">directory <code>src/filters/</code></a>.</p>
  <p>I like to put all modules under the <code>\modules\</code> namespace, with sub-namespaces for each module. For example, for a module that extends the Webhooks plugin, I would use <code>\modules\CustomWebhooks\</code> as a namespace. So this would result in the following directory structure:</p>
  <pre><code>modules
  ├── CustomWebhooks
  │   ├── CustomWebhooksModule.php
  │   └── filters
  │       └── ArticleFilter.php
  </code></pre>
  <p>And the following fully qualified class names:</p>
  <ul>
  <li><code>CustomWebhooksModule.php</code> -&gt; <code>\modules\CustomWebhooks\CustomWebhooksModule</code></li>
  <li><code>ArticleFilter.php</code> -&gt; <code>\modules\CustomWebhooks\filters\ArticleFilter</code></li>
  </ul>
  <p>Optionally, you can also put the <code>filters</code> and every other subdirectory into a <code>src</code> directory inside <code>modules/CustomWebhooks</code>, this depends on your autoload setup. In this case, the fully qualified class names don't change, but the directory structure looks like this:</p>
  <pre><code>modules
  ├── CustomWebhooks
  │   ├── CustomWebhooksModule.php
  │   └── src
  │       └── filters
  │           └── ArticleFilter.php
  </code></pre>
  
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2022-01-17T10:25:32.963Z
Answers.Text: Thank you! I followed as straghit as possible your indications and I think that works. But just for a reason I still don't undertand, I had to add `abstract` before `class ArticleFilter implements FilterInterface` to make it works.
Answers.UserDisplayName: Romain P.
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2022-01-17T10:30:18.113Z
Answers.Text: @RomainPoirier That won't work – [abstract classes can't be instantiated](https://www.php.net/manual/en/language.oop5.abstract.php), they're meant as base classes for other classes to extend. If you were getting an error that was fixed by making the class abstract, your class is probably missing one of the methods [required by the interface](https://github.com/craftcms/webhooks/blob/develop/src/filters/FilterInterface.php). Remove abstract from the class definition and check the error message to see what you're missing!
Answers.UserDisplayName: MoritzLost
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2022-01-19T11:07:23.170Z
Answers.Text: This is what I get if I remove `abstract`: `Class modules\utilitiesmodule\filters\CompaniesFilter contains 1 abstract method and must therefore be declared abstract or implement the remaining methods (craft\base\ComponentInterface::isSelectable)`. My code is almost a copy/paste of the example in the [doc](https://github.com/craftcms/webhooks#filtering-events), I don't undestand what's missing.
Answers.UserDisplayName: Romain P.
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2022-01-19T11:17:11.773Z
Answers.Text: @RomainPoirier You're missing the `isSelectable` method of the [ComponentInterface](https://github.com/craftcms/cms/blob/main/src/base/ComponentInterface.php). The example code in the readme would result in this error as well – maybe post an issue about that on Github. The built-in filters all extend the [BaseElementFilter class](https://github.com/craftcms/webhooks/blob/develop/src/filters/BaseElementFilter.php), you could do that as well. This one extends the [`Component` base class](https://docs.craftcms.com/api/v3/craft-base-component.html) which includes the missing method.
Answers.UserDisplayName: MoritzLost
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2022-01-19T11:18:35.773Z
Answers.Text: @RomainPoirier So your definition would look like this: `class ArticleFilter extends BaseElementFilter implements FilterInterface`. Make sure to add `use` statements at the top for the classes / interfaces you're using.
Answers.UserDisplayName: MoritzLost
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2022-01-24T10:29:32.647Z
Answers.Text: Thank you. Now I get this error: `Class 'modules\utilitiesmodule\filters\BaseElementFilter' not found`. How do you load the `BaseElementFilter` class?
Answers.UserDisplayName: Romain P.
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2022-01-24T10:58:46.040Z
Answers.Text: @RomainPoirier You need to configure your `composer.json` to tell the autoloader where to find your modules files. Make sure to use `composer dump-autoload -a` afterwards. Read the guide on [how to build a module](https://craftcms.com/docs/3.x/extend/module-guide.html), this includes a section on how to set up the autoloader for modules.
Answers.UserDisplayName: MoritzLost
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2022-01-26T10:47:35.360Z
Answers.Text: Thank you, my autoload was correct and `dump-autoload` triggered: my module is working fine for others scripts. I now get this error: `Class 'modules\utilitiesmodule\filters\ArticleFilter' not found`
  . This was added on top of src/utilitiesmodules/src: `use modules\utilitiesmodule\filters\ArticleFilter as ArticleFilter`. And this was added in `config/app.php`: `'modules' => [ 'utilities-module' => [ 'class' => \modules\utilitiesmodule\UtilitiesModule::class, 'components' => [ 'articleFilter' => [ 'class' => 'modules\utilitiesmodule\filters\ArticleFilter' ] ] ] ]`. Any idea what's still wrong?
Answers.UserDisplayName: Romain P.
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2022-01-26T10:52:43.123Z
Answers.Text: @RomainPoirier Why are there two `src` folders in the path? The modules definition is a bit unusual, looks like a mix of different styles to define components/modules, probably just a mixup. Anyway, pretty hard to read code in the comments – please post this as a new question and include both the directory structure (`tree` output), the class files and the autoload setup in your `composer.json`.
Answers.UserDisplayName: MoritzLost
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2022-01-31T08:27:07.620Z
Answers.Text: Sorry that was a typo, the correct path is `/modules/utilitiesmodule/src/UtilitiesModule.php` (only one `src` in the path). Ok, will do it, thank your for your help.
Answers.UserDisplayName: Romain P.
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2022-01-31T08:48:47.803Z
Answers.Text: Following question: https://craftcms.stackexchange.com/questions/38962/difficulties-to-setup-a-filter-class.
Answers.UserDisplayName: Romain P.
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2022-02-01T09:19:05.740Z
Answers.Text: @RomainPoirier If you consider my answer to this particular issue sufficient, don't forget to mark it as accepted. Thanks!
Answers.UserDisplayName: MoritzLost
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2022-01-14T14:42:31.610Z
Answers.LastActivityDate: 2022-01-14T14:42:31.610Z
Answers.UserDisplayName: MoritzLost
Body: <p>I have a custom Module and I would like to implement the <code>craft\webhooks\filters\FilterInterface</code> as seen on the <a href="https://github.com/craftcms/webhooks#filtering-events" rel="nofollow noreferrer">doc</a>.</p>
  <p>I understand that the event <code>Webhooks::EVENT_REGISTER_FILTER_TYPES</code> should be added in the <code>public function init()</code> of my Module, but I don't know where to store the class <code>ArticleFilter implements FilterInterface</code>.</p>
  <p>Is it under <code>/controllers</code>, <code>/services</code>, <code>/models</code>,... or something else?
  I don't understand the logic and where to store this filter.</p>
  
Tags: <modules><plugin-webhooks>
Title: Where to implement Craft Webhook FilterInterface
ThreadText: # Where to implement Craft Webhook FilterInterface
  
  (Asked by: username_0 on 2022-01-14)
  
  I have a custom Module and I would like to implement the `craft\webhooks\filters\FilterInterface` as seen on the [doc](https://github.com/craftcms/webhooks#filtering-events).
  
  I understand that the event `Webhooks::EVENT_REGISTER_FILTER_TYPES` should be added in the `public function init()` of my Module, but I don't know where to store the class `ArticleFilter implements FilterInterface`.
  
  Is it under `/controllers`, `/services`, `/models`,... or something else?
  I don't understand the logic and where to store this filter.
  
  **Tags:** modules, plugin-webhooks
  
  
  ---
  
  ## 1 answers
  
  ### Answer by username_1 on 2022-01-14. Score: 2 | Accepted answer
  
  It doesn't *really* matter as long as you make sure to type-hint correctly relative to the current namespace and/or use the fully qualified class name. However, it's best to follow the established conventions of the core or in this case, the plugin you're building on. The Webhooks plugin puts all the default filters in the [directory `src/filters/`](https://github.com/craftcms/webhooks/tree/develop/src/filters).
  
  I like to put all modules under the `\modules\` namespace, with sub-namespaces for each module. For example, for a module that extends the Webhooks plugin, I would use `\modules\CustomWebhooks\` as a namespace. So this would result in the following directory structure:
  
  ```
  modules
  ├── CustomWebhooks
  │   ├── CustomWebhooksModule.php
  │   └── filters
  │       └── ArticleFilter.php
  
  ```
  
  And the following fully qualified class names:
  
  * `CustomWebhooksModule.php` -> `\modules\CustomWebhooks\CustomWebhooksModule`
  * `ArticleFilter.php` -> `\modules\CustomWebhooks\filters\ArticleFilter`
  
  Optionally, you can also put the `filters` and every other subdirectory into a `src` directory inside `modules/CustomWebhooks`, this depends on your autoload setup. In this case, the fully qualified class names don't change, but the directory structure looks like this:
  
  ```
  modules
  ├── CustomWebhooks
  │   ├── CustomWebhooksModule.php
  │   └── src
  │       └── filters
  │           └── ArticleFilter.php
  
  ```
  
  > **Comments:**
  > **username_0**: Thank you! I followed as straghit as possible your indications and I think that works. But just for a reason I still don't undertand, I had to add `abstract` before `class ArticleFilter implements FilterInterface` to make it works.  
  > **username_1**: @RomainPoirier That won't work – [abstract classes can't be instantiated](https://www.php.net/manual/en/language.oop5.abstract.php), they're meant as base classes for other classes to extend. If you were getting an error that was fixed by making the class abstract, your class is probably missing one of the methods [required by the interface](https://github.com/craftcms/webhooks/blob/develop/src/filters/FilterInterface.php). Remove abstract from the class definition and check the error message to see what you're missing!  
  > **username_0**: This is what I get if I remove `abstract`: `Class modules\utilitiesmodule\filters\CompaniesFilter contains 1 abstract method and must therefore be declared abstract or implement the remaining methods (craft\base\ComponentInterface::isSelectable)`. My code is almost a copy/paste of the example in the [doc](https://github.com/craftcms/webhooks#filtering-events), I don't undestand what's missing.  
  > **username_1**: @RomainPoirier You're missing the `isSelectable` method of the [ComponentInterface](https://github.com/craftcms/cms/blob/main/src/base/ComponentInterface.php). The example code in the readme would result in this error as well – maybe post an issue about that on Github. The built-in filters all extend the [BaseElementFilter class](https://github.com/craftcms/webhooks/blob/develop/src/filters/BaseElementFilter.php), you could do that as well. This one extends the [`Component` base class](https://docs.craftcms.com/api/v3/craft-base-component.html) which includes the missing method.  
  > **username_1**: @RomainPoirier So your definition would look like this: `class ArticleFilter extends BaseElementFilter implements FilterInterface`. Make sure to add `use` statements at the top for the classes / interfaces you're using.  
  > **username_0**: Thank you. Now I get this error: `Class 'modules\utilitiesmodule\filters\BaseElementFilter' not found`. How do you load the `BaseElementFilter` class?  
  > **username_1**: @RomainPoirier You need to configure your `composer.json` to tell the autoloader where to find your modules files. Make sure to use `composer dump-autoload -a` afterwards. Read the guide on [how to build a module](https://craftcms.com/docs/3.x/extend/module-guide.html), this includes a section on how to set up the autoloader for modules.  
  > **username_0**: Thank you, my autoload was correct and `dump-autoload` triggered: my module is working fine for others scripts. I now get this error: `Class 'modules\utilitiesmodule\filters\ArticleFilter' not found` . This was added on top of src/utilitiesmodules/src: `use modules\utilitiesmodule\filters\ArticleFilter as ArticleFilter`. And this was added in `config/app.php`: `'modules' => [ 'utilities-module' => [ 'class' => \modules\utilitiesmodule\UtilitiesModule::class, 'components' => [ 'articleFilter' => [ 'class' => 'modules\utilitiesmodule\filters\ArticleFilter' ] ] ] ]`. Any idea what's still wrong?  
  > **username_1**: @RomainPoirier Why are there two `src` folders in the path? The modules definition is a bit unusual, looks like a mix of different styles to define components/modules, probably just a mixup. Anyway, pretty hard to read code in the comments – please post this as a new question and include both the directory structure (`tree` output), the class files and the autoload setup in your `composer.json`.  
  > **username_0**: Sorry that was a typo, the correct path is `/modules/utilitiesmodule/src/UtilitiesModule.php` (only one `src` in the path). Ok, will do it, thank your for your help.  
  > **username_0**: Following question: https://craftcms.stackexchange.com/questions/38962/difficulties-to-setup-a-filter-class.  
  > **username_1**: @RomainPoirier If you consider my answer to this particular issue sufficient, don't forget to mark it as accepted. Thanks!  
  
  ---
  
  