Package controller bootstrap flow

Permalink
I'm currently upgrading one of my add-ons on the marketplace. I want to implement Doctrine ORM for my model. Concrete5 uses this ORM so it seems like a good idea to do the same. I'm also implementing dependency injection using my own service provider.

But I'm running into a number of issues. There's basically three things that need to happen in this particular order:
1.) Register my class files with the PSR4 autoloader
2.) Register the annotation driver for my model's namespace
3.) Register my service provider

I have all that code setup and working. The problem is the order in which a package controller does it's bootstrap/setup. I'm using the Concrete\Core\Database\EntityManager\Provider\StandardPackageProvider to register my annotationsdriver as described here:

https://documentation.concrete5.org/developers/packages/custom-datab...

. So I have this method in my package controller:
public function getEntityManagerProvider() {
   $provider = new StandardPackageProvider($this->app, $this, [
      'src/Entity' => '\\Concrete\\Package\\MyPackage\\Src\\Entity\\'
   ]);
   return $provider;
}


This method is called by Concrete after the 'on_start' method is called. It's in 'on_start' where I register the autoloader and my service provider. But the service provider binds classes that need to access my models from Doctrine and at that point it hasn't been registered with the annotations driver by Concrete, so my code breaks. It seems to me Concrete should register the annotations driver first before calling on_start.

My on_start method:
public function on_start() {
      $this->registerWithAutoloader();
      $this->registerServiceProvider();
   }


Even if this gets solved then I also need this to happen before the install method is called because I need the repository and the model to create database records.

I managed to make things work by stripping the code that registers the drivers from Concrete's code and putting this in my package controller so I can register the driver at my own discretion but this is not ideal.

Any ideas on the subject?

Justin1978
View Replies: View Best Answer
A3020 replied on at Permalink Best Answer Reply
A3020
How about adding your service provider logic to a method 'on_after_packages_start' in your pkg controller? See /concrete/src/Application/Application.php
Justin1978 replied on at Permalink Reply
Justin1978
I wasn't aware of that hook. I'll give that a try, thanks!
Justin1978 replied on at Permalink Reply
Justin1978
I wasn't aware of that hook. I'll give it a try, thanks!

On Sat, Aug 11, 2018, 11:55 concrete5 Community <[email protected]>
wrote:
Justin1978 replied on at Permalink Reply
Justin1978
I wasn't aware of that hook. I'll give it a try, thanks!

On Sat, Aug 11, 2018, 11:55 concrete5 Community <[email protected]>
wrote:
JohntheFish replied on at Permalink Reply
JohntheFish
You could be making this more complicated than it needs to be.
You can declare pkgAutoloaderRegistries for a namespace for your own classes and put your doctrine entities where the core already expects to see them.
Justin1978 replied on at Permalink Reply
Justin1978
Well, I tried that but it didn't work. It's possible I didn't something else wrong so I'll give it another try. But I'm not sure that will solve the problem seeing how Concrete will probably just access that property instead of calling that method after on_start is called.
Justin1978 replied on at Permalink Reply
Justin1978
I think that didn't work for some reason but I'll give it another try.

But won't this still be done in the same order as it is now? Because that
will still not solve my problem. Seems to.me concrete will just check that
property instead of calling the method.

On Sat, Aug 11, 2018, 14:03 concrete5 Community <[email protected]>
wrote:
Justin1978 replied on at Permalink Reply
Justin1978
I think that didn't work for some reason but I'll give it another try.

But won't this still be done in the same order as it is now? Because that
will still not solve my problem. Seems to.me concrete will just check that
property instead of calling the method.

On Sat, Aug 11, 2018, 14:03 concrete5 Community <[email protected]>
wrote:
Justin1978 replied on at Permalink Reply
Justin1978
Solved! Thanks for your replies. The 'on_after_packages_start' tip worked for me. Also used $pkgAutoloaderRegistries as John suggested.

I'll include some of the code from my package controller here in case anyone else stumbles upon this topic with the same question:

My Doctrine registration:
/**
    * {@inheritdoc}
    */
   protected $pkgAutoloaderRegistries = [
      'src/Entity' => '\\Concrete\\Package\\MyPackage\\Src\\Entity\\'
   ];


My autoload registration in the on_start hook;
public function on_start() {
      $this->registerWithAutoloader();
   }


And finally registering the service provider:

/**
    * Hook.
    * @return void
    */
   public function on_after_packages_start() {
      if (!$this->isUpToDate()) {
         // Can't register the service provider because it can throw an exception if we are in the process of upgrading.
         return;
      }
      $this->registerServiceProvider();
   }