0

I'm working with a Symfony 3.4 (PHP 7.2, update to 7.4 soon) project. I have some classes who extends an abstract class and i would like all my classes got the same constant name (constant have value different in each class). I'm starting with a pattern like this :

abstract class AbstractClass
{
    abstract public function getConstant(): string;
}

final class Foo extends AbstractClass
{
    const MY_CONST = 'foo';

    public function getConstant(): string
    {
        return self::MY_CONST;
    }
}

final class Bar extends AbstractClass
{
    const MY_CONST = 'bar';

    public function getConstant(): string
    {
        return self::MY_CONST;
    }
}

// echo $foo->getConstant() : 'foo'
// echo $bar->getConstant() : 'bar'

The goal: if a class who extends AbstractClass don't have MY_CONST, i want return an message error. I have excluded theses solutions :

  • I can't add a constant in an interface (maybe in PHP 8 ?)
  • I can't use "abstract factory" pattern for a constant (in my code it runs with getConstant() method
  • I can't use a static property

The only way i have found is : implement an interface and tag the interface like explain in documentation. With compilerpass, helped with ReflexionClass, i will check if constant name exist, and if not: thrown an error or something like this.

So, i've edit like this :

final class Foo extends AbstractClass implements MyCustomInterface
{
     // ...
}

final class Bar extends AbstractClass implements MyCustomInterface
{
    // ...
}

The interface :

interface MyCustomInterface
{
}

Adding tag in AppKernel.php

    protected function build(ContainerBuilder $container): void
    {
        $container
            ->registerForAutoconfiguration(MyCustomInterface::class)
            ->addTag('my_custom_tag');
    }

And a compilerpass :

class MyCustomPass implements CompilerPassInterface
{
    public function process(ContainerBuilder $container): void
    {
        if (!$container->has(MyCustomInterface::class)) {
            dump('No interface found');
            return;
        }

        $definition = $container->findDefinition(MyCustomInterface::class);
        $taggedServices = $container->findTaggedServiceIds('my_custom_tag');
        dump($taggedServices);
    }
}

The fun begin here...if i have only ONE class who implement the interface, $taggedServices find the service. BUT, if more than one class implements interface, no class are found...

I don't find where i am wrong. Do i need to implements AbstractClass instead of children classes ?

6
  • Your question seems to be jumping all over the place what with all the CONST distractions. Your code at the end for tagging all services that implement a given interface seems correct. Here is a working example that seems to match your code. I suppose it is possible that not all of your classes are getting picked up by autowire? Does bin/console debug:container show all the expected services? Commented Nov 24, 2021 at 14:45
  • 1
    Is the $container->has(interface) failing? That is to be expected. When more than one class for a given interface exists the container does not know which interface to automatically inject. Hence no interface service will be automatically created. Commented Nov 24, 2021 at 14:54
  • @Cerad your second post seems to explain why $container->has(interface) failing. So i think using Interface is not the solution i need. thank you for answer. Have you an idea for forcing a class to have a specific constant name when extends abstract or implements specific interface ? Commented Nov 24, 2021 at 15:11
  • It seems like you could still use your posted code. findTaggedServiceIds will still return a list of service definitions from which you get the class name and then use reflection to look for the const. I suppose you could also try posting a new and very much slimmed down question using the PHP tag. But to be honest, I'd focus on figuring out an alternative approach to having the const requirement in the first place. Can you explain, in a few words, why you need this? Commented Nov 24, 2021 at 15:19
  • 1/ In few words: i'm working on CMS ezPlatform 2.5 (preparation for upgrade to Ibexa Platform 3.3) and i'm building a factory who transform Content (data in CMS) into DTO. I'm using a couple DTO/Repository for each content type. Each repository class got two methods: one return my famous const of above, which contains a content type identifier. Second method return linked DTO with "return MyDTO::class".Factory is called in abstract repository. So when i'm building a DTO, i know which type i need to transform. Commented Nov 26, 2021 at 7:36

0

Your Answer

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

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.