0

I am trying to create a hook extension for Contao. But Contao doesn't seem to be able to load my class from the namespace, which handles the hook. This is my file structure:

I have tried changing names and added ".php" to the class, looked up tutorials, but I can't find what I am doing wrong. I am fairly inexperienced in this topic, so I might be missing something obvious.

autoload.php

ClassLoader::addNamespaces(array 
    ( 
        'Memberlevels', 
    )); 

gister PSR-0 namespace 
 */ 
if (class_exists('NamespaceClassLoader')) { 
    NamespaceClassLoader::add('Memberlevels', 'system/modules/memberlevels/classes'); 
} 


if (class_exists('NamespaceClassLoader')) { 
    NamespaceClassLoader::addClassMap(array 
        ( 

            'Memberlevels'                => 'system/modules/memberlevels/classes/myClass.php' 
        )); 
} 

/* 
 * Register the templates 
 */ 
TemplateLoader::addFiles([ 
    'cookiebar' => 'system/modules/memberlevels/templates', 
]);  

config.php

$GLOBALS['TL_HOOKS']['outputBackendTemplate'][] = array('Memberlevels\myClass', 'myOutputBackendTemplate');  

I get the error message:

Attempted to load class "myClass" from namespace "Memberlevels". Did you forget a "use" statement for another namespace?

barbsan
  • 3,418
  • 11
  • 21
  • 28
Bladerxdxi
  • 111
  • 1
  • 8

1 Answers1

1

You are still using the old Contao 3 way of loading classes. In Contao 4, you should use the autoloading feature of composer. The default composer.json of the most recent Contao versions already include autoloading directives for the src/ folder of your Contao installation:

"autoload": {
    "psr-4": {
        "App\\": "src/"
    }
},

Using that, this is how you create & register a hook in a Contao 4.4 compatible way:

// src/EventListener/OutputBackendTemplateListener.php

namespace App\EventListener;

class OutputBackendTemplateListener
{
    public function onOutputBackendTemplate(string $buffer, string $template): string
    {
        // Do something 
        return $buffer;
    }
}
// app/Resources/contao/config/config.php

$GLOBALS['TL_HOOKS']['outputBackendTemplate'][] = [\App\EventListener\OutputBackendTemplateListener::class, 'onOutputBackendTemplate'];

Starting with Contao 4.8 you can also use annotations to register a hook, eliminating the need to register the hook in app/Resources/contao/config/config.php.

fritzmg
  • 2,494
  • 3
  • 21
  • 51
  • So, Contao 3 Extensions don't work if i copy them to a Contao 4.4 System? I thought they were compatible. At least when it comes to hooks. – Bladerxdxi Aug 12 '19 at 09:49
  • I added the composer.json but the only change is, that the error now showsd in the log, and not as a displayed error in the backend. – Bladerxdxi Aug 12 '19 at 09:54
  • I did not say that Contao 3 extensions do not work in Contao 4. I merely said that you are still using the old way and I showed you the recommended way ;) – fritzmg Aug 12 '19 at 10:24
  • Ah, i see. But you don't know what actually the problem is? – Bladerxdxi Aug 12 '19 at 10:28
  • The problem might be, that you are using the _NamespaceClassLoader_. If you still want to load the classes like in Contao 3, you probably have to do it without the _NamespaceClassLoader_ extension (unless you installed it as well - which I would not recommend anyway). – fritzmg Aug 12 '19 at 10:33
  • I now add the namespaces like in the first 4 lines. Doesn't work as well. – Bladerxdxi Aug 14 '19 at 06:57
  • What do you mean "like in the first 4 lines"? – fritzmg Aug 14 '19 at 09:21
  • If you are still trying the old way - this is how you load classes in Contao 3: https://github.com/contao/core/blob/e38d7e62fef58a73bfcd7a96fe6f303073808d01/system/modules/core/config/autoload.php#L12-L259 – fritzmg Aug 14 '19 at 09:25
  • I just converted this extension into a bundle Link here:https://github.com/localbranding-de/membershiplevels-bundle I have tried setting up the namespaces like you said, but i still get the same error. I seem to get something real wrong when it comes to namespaces here. – Bladerxdxi Aug 15 '19 at 07:46
  • You are using a classmap in your `composer.json`. Don't put any classes in `src/Resources/contao`. Use your defined namespace. – fritzmg Aug 15 '19 at 07:50
  • So i put the classes folder in src? And remove the classmap? And i see plenty of extensions that have their classes for hooks and stuff in src/Resources/contao – Bladerxdxi Aug 15 '19 at 07:56
  • Just do it like in my example. A class for a hook should go into the `EventListener` namespace for example. Technically it does not matter where the class is - you are free to define your classes anywhere. But it makes sense to keep a certain structure. Also you should follow basic PHP coding guidlines. For instance, your class should not be called `honischClass`. First of all you should use camel case, secondly your class name should reflect on what the class actually does. – fritzmg Aug 15 '19 at 07:58
  • I build it the way you suggested, but the error stays `Attempted to load class "OutputBackendTemplateListener::class" from namespace "LocalbrandingDe\MembershiplevelsBundle\EventListener". Did you forget a "use" statement for another namespace?` – Bladerxdxi Aug 15 '19 at 08:14
  • It should work, as far as I can see. Remember to not use the `--optimize-autoloader` option during the development. If you ran your `composer update` or `install` operation with `-o`/`--optimize-autoloader`, you need to run `composer dump-autoload`. – fritzmg Aug 15 '19 at 08:54
  • I use `php contao-manager.phar.php composer update --prefer-dist` to install/update the package. The hello world module is working fine (it does get displayed in the frontend). Also when i dublicate the `OutoutBackendTemplateListener` i get the error message, that the class name is already in use. So it has to be registered somewhere, just not the namespace i want apperently. – Bladerxdxi Aug 15 '19 at 09:08
  • You made a syntactical error. you wrote `['LocalbrandingDe\MembershiplevelsBundle\EventListener\OutputBackendTemplateListener::class', 'myOutputBackendTemplate'];`, but it should be either `['LocalbrandingDe\MembershiplevelsBundle\EventListener\OutputBackendTemplateListener', 'myOutputBackendTemplate'];` or `[\LocalbrandingDe\MembershiplevelsBundle\EventListener\OutputBackendTemplateListener::class, 'myOutputBackendTemplate'];` – fritzmg Aug 15 '19 at 10:34
  • Ah, yes. It works. Thank you. So it needs string (example 1) or an object (example 2). That was probably it, and there was nothing wrong with the namespaces. – Bladerxdxi Aug 15 '19 at 12:53
  • The second example is also a string :). Using `::class` resolves the class name to a string. – fritzmg Aug 15 '19 at 17:29