Routing nested controllers using IoC for dependency injection in laravel 3 - dependency-injection

update: if i can achieve same result using a different approach, please enlighten me.
I'm using/learning laravel 3 while building my project. Before coding any page-content at all, I'm verifying if i can deploy everything as planned, since this project is an actual rewrite of a rather huge app which is seriously outdated in the techniques it uses.
I'm struggling at this last part, which is quite possibly the hardest challenge i'll face to setup my project.
URL:
site.com/shops/__identifier__/controller/action/params
The above is the uri i'm trying to code atm.
The _identifier_ part should become a model (eloquent based)
the shops is the base for nested controllers
ie:
controllers/
- shops/
- home.php
- contact.php
- products.php
- etc ....
Each existing uri shops/identifier is a real site on its own. (though it has a different domain offcourse)
I want all my nested shops controllers to know what shop they're working with. In fact, the identifier will be used to load the correct layouts, to render the correct images, contact details etc...
From what i've read, i'll need to use the IoC functionality to inject the dependency of my shop-model into the constructor of my controller.
this is what i have atm:
file:application/start.php
/**
* Register IoC container for my nested shop controllers
*/
IoC::register('controller: shop', function($controller, $identifier)
{
//also tried using same line without the \\
$class = '\\Shops_' . ucfirst($controller) . '_Controller';
return new $class($identifier);
});
file:application/routes.php
/**
* Register all shop routes
*/
Route::any('/shops/(:any)/(:any?)/(:any?)', function($identifier, $controller = "home", $method = "index", $params = array()){
if($controller === "index")
$controller = "home";
$controller = IoC::resolve('controller: shop', array($controller, $identifier));
return $controller;
});
shop base-controller located at application/libraries/controllers/shop.php
<?php
namespace Controllers;
use Base_Controller;
/**
* Shop controller
*/
class Shop extends Base_Controller
{
public function __construct($identifier){
/**
* #todo: load the shop model using the identifier
* possibly move this after the parent::__construct()
*/
parent::__construct();
}
}
file: applications/controllers/shops/home.php
<?php
/**
* #heads up: Shop_Controller is aliased in application/config/application.php
*/
class Shops_Home_Controller extends Shop_Controller
{
public function get_index(){
return ('test');
}
}
Problems:
when defining my routes for these nested shops controllers. Do i simply return the controller laravel should use to resolve the request, or do i trigger the action myself in the callback function in that route definition?
controllers aren't autoloading (when trying the implementation above), yet i'm using the correct conventions for those controllers (unless i'm missing something :-) ). I'm guessing this is because i'm using IoC, how do i cleanly implement this or what is my mistake?
how do i trigger the correct action? It should, as expected, trigger the corresponding HTTP-verb action, since my nested controllers are also RESTFUL-controllers.
extra question to keep things as clean as possible: 'index' defaults to home controller when not using IoC functionality. Is my solution (if-condition in routes.php) to mimic this functionality a clean one? or is there any better approach?
By all means:
If my approach is way off, please tell me, i'm a newbie at laravel, and it's the first framework i'm using, so i'm a newbie at frameworks in general.
I'd also like to apologize if my question isn't explained to well so feel free to ask extra info.
I tried my best at googling this problem, but couldn't find anything similar, which is a first, since all my other laravel problems were easily solved using google.
I'd kindly thank anyone taking the time to read this and even better send me in the right direction!

Ok, final solution, this is far from clean if you ask me, but it seems to work, at least as far as i've checked.
I'm also not to sure if there is an alternative, but due to lack of response and timepressure, i decided to go with this and keep fingers crossed :(.
//start.php
IoC::register('controller: shop', function($id, $controllerName){
//controller name is the name of the controller located in the shops map
$class = "Shops_" . ucfirst($controllerName) . "_Controller";
include(path('app') . 'controllers/shops/' . strtolower($controllerName) . '.php');
return new $class($id);
});
//routes.php
Route::any("shops/(:any)/(:any?)/(:any?)/(:all?)", function($id, $controller = "index", $action = "index", $params = ""){
if($controller === "index")
$controller = "home";
$params = explode('/', $params);
$controller = IoC::resolve("controller: shop", array($id, $controller));
$http_verb = Request::method();
/**
* Need to return this, and i now need to manually return every response in every action in every shop controller
*/
return call_user_func_array(array($controller, $http_verb . '_' . $action), $params);
});
so example given
class Shops_Home_Controller extends Shop_Controller
{
public function get_index(){
/**
* this works when doing things the usual way, but will not return any output
* when working with nested dependency injection
*/
$this->layout->nest('content', 'shops.index');
}
public function get_test(){
/**
* this needs to return layout object if it is to work with the nested dependency injection
*/
$this->layout->nest('content', 'shops.index');
}
}

Related

ZF2, dependencies which I don't know at start

In my controller, via service, I get from DB a list of the names of widgets (eg. chart, calendar, etc). Every widget implements WidgetInterface and may need other services as its own dependencies. The list of widgets can be different for each user, so I don't know which widgets / dependencies I will need in my controller. Generally, I put dependencies via DI, using factories, but in this case I don't know dependencies at the time of controller initialization.
I want to avoid using service locator directly in controller. How can I manage that issue? Should I get a list of the names of widgets in controller factory? And depending on widgets list get all dependencies and put them to controller?
Thanks, Tom
Solution
I solved my issue in a way that suggested Kwido and Sven Buis, it means, I built my own Plugin Manager.
Advantages: I do not need use service locator directly in controller and I have clear and extensible way to get different kinds of widgets.
Thank you.
Create your own Manager, like some sort of ServiceManager, for your widgets.
class WidgetManager extends AbstractPluginManager
Take a look at: Samsonik tutorial - pluginManager. So this way you can inject the WidgetManager and only retrieve the widgets from this manager as your function: validatePlugin, checks whether or not the fetched instance is using the WidgetInterface. Keep in mind that you can still call the parent ServiceManager.
Or keep it simple and build a plugin for your controller that maps your widget names to the service. This plugin can then use the serviceLocator/Manager to retrieve your widget(s), whether they're created by factories or invokableFactories. So you dont inject all the widget directly but only fetch them when they're requested. Something realy simplistic:
protected $map = [
// Widget name within the plugin => Name or class to call from the serviceManager
'Charts' => Widget\Charts::class,
];
public function load($name)
{
if (array_key_exists($name, $this->map)) {
return $this->getServiceManager()->get($this->map[$name]);
}
return null;
}
Injecting all the Widgets might be bad for your performance so you might consider something else, as when the list of your widgets grow so will the time to handle your request.
Hope this helped you and pushed you in some direction.
This indeed is a interesting question. You could consider using Plugins for the widgets, which can be loaded on the fly.
Depency injection is a good practise, but sometimes, with dynamic content, impossible to implement.
Another way to do this, is to make your own widget-manager. This manager then can load the specific widgets you need. The widget-manager can be injected into the controller.
Edit:
As you can see above, same idea from #kwido.
I would use a separate service and inject that into the controller.
interface UserWidgetServiceInterface
{
public function __construct(array $widgets);
public function getWidget($name);
}
The controller factory
class MyControllerFactory
{
public function __invoke(ControllerManager $controllerManager, $name, $requestedName)
{
$serviceLocator = $controllerManager->getServiceLocator();
$userWidgetService = $serviceLocator->get('UserWidgetService');
return new MyController($userWidgetService);
}
}
Then the logic to load the widgets would be moved to the UserWidgetServiceFactory.
public function UserWidgetServiceFactory
{
public function __invoke(ServiceManager $serviceLocator, $name, $requestedName)
{
$userId = 123; // Load from somewhere e.g session, auth service.
$widgetNames = $this->getWidgetNames($serviceLocator, $userId);
$widgets = $this->loadWidgets($serviceManager, $widgetNames);
return new UserWidgetService($widgets);
}
public function getWidgetNames(ServiceManager $sm, $userId)
{
return ['foo','bar'];
}
public function loadWidgets(serviceManager $sm, array $widgets)
{
$w = [];
foreach($widgets as $widgetName) {
$w[$widgetName] = $sm->get($widgetName);
}
return $w;
}
}
The call to loadWidgets() would eager load all the widgets; should you wish to optimise this you could register your widgets as LazyServices

How do you call a Service outside of a Symfony3 controller? And queries from Repository

I have two questions today. This is detailed because too many other replies rely on assumptions and have not been detailed enough. I hope that this is detailed and will be able to help lots of developers.
1st. The code below points to the real question I have. How do you call a Service outside of the controller since the $this->get() method is inside of the controller only? This is not in any of the documentation or on KNP University's tutorial on Services.
2nd. From what I have read, according to some, not all, if you call to a Repository, from anywhere, it should automatically instantiate the Entity Repository. I don't think this is so. Tell me if I am right or wrong.
See the following below....
My Default Controller, it's straightforward call a class and let it do some work. As an example, I called it with a Service and a conventional OO method:
<?php
// src/AppBundle/Controller/DefaultController.php
// Here is where I am starting. There is a service
// and there is a conventional OO call.
// Both should invoke the same thing.
namespace AppBundle\Controller;
use AppBundle\Service;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Request;
class DefaultController extends Controller
{
/**
* #Route("/", name="homepage")
*/
public function indexAction(Request $request)
{
// Step 1.... Do a little of this.
// Step 2.... Do some of that.
// Step 3.... Call another class to do some logic and it will
// eventually call a query...
// Invoking my service
$obj_via_service = $this->get('app.services.process_question');
$result1 = $obj_via_service->submitQuestion();
// Invoking via Namespace and Call
$obj_via_new = new Service\ProcessQuestion();
$result2 = $obj_via_new->submitQuestion();
dump($result1);
dump($result2);
die();
}
}
My Service.yml File.
# src/app/config/services.yml
parameters:
services:
app.services.process_question:
class: AppBundle\Service\ProcessQuestion
app.rep.geo_state:
class: AppBundle\Entity\GeoStateRepository
arguments: ['#doctrine.orm.entity_manager']
This is my class that is doing the work for me. I want to be able to call the second service ^^above^^ but I can't because I can't use $this->get() outside of the controller.
<?php
// src/AppBundle/Service/ProcessQuestion.php
namespace AppBundle\Service;
class ProcessQuestion
{
public function submitQuestion()
{
// Step 1.... Do this.
// Step 2.... Do that.
// Step 3.... Query for some data...
// Invoke my repository class via a Service Call....
// but I cannot do that because 'get' is a part of the
// controller...
$obj_via_service = $this->get('app.rep.geo_state');
**^^ ^^**
**^^ This is what won't work ^^**
$results = $obj_via_service->selectStates();
return $results;
}
}
My Repository Class... Keep in mind I cannot reach this class yet, but I am throwing it in here so that other new Symfony 3 developers can see this.
<?php
// src/AppBundle/Repository/GeoState.php
// My Repository Class where I want to do some queries...
namespace AppBundle\Repository;
use Doctrine\ORM\EntityRepository;
class GeoStateRepository extends EntityRepository
{
/**
* #Mapping\Column(type="string")
*/
private $em;
public function __construct(EntityManager $em)
{
$this->em = $em;
}
public function selectStates()
{
$sql = "SELECT * FROM geo_state";
return $this->getEntityManager()->createQuery($sql)->getResult();
}
}
Why is this so hard to find an example? Also, I have followed a bunch of the Symfony 2.x documentation and the nuances are hard to port into Symfony 3 sometimes.
I think Fabian re purposed too much of the docs for 2.x to go into 3.x and there is not any good examples on coding that is between the New Developer level and the Hard Core Developer level. If you are at Sensio and reading this, please keep in mind that there is a middle ground we need to cover and most of the screencasts that out there and much of the better documentation is not in English.
You should really read more about Dependency Injection.
Symfony is very good at this .
Regarding your question about using app.rep.geo_state service in the app.services.process_question service .
In Symfony/ DI terminology it's can be termed as injecting a service into another service .
The documentation on how to do this is very good.
this is how it can be done.
services:
app.services.process_question:
class: AppBundle\Service\ProcessQuestion
arguments: ['#app.rep.geo_state']
app.rep.geo_state:
class: AppBundle\Entity\GeoStateRepository
arguments: ['#doctrine.orm.entity_manager']
And in the class
<?php
// src/AppBundle/Service/ProcessQuestion.php
namespace AppBundle\Service;
use AppBundle\Entity\GeoStateRepository;
class ProcessQuestion
{
private $geoRepository;
public function __construct(GeoStateRepository $geoRepository)
{
$this->geoRepository = $geoRepository;
}
public function submitQuestion()
{
//now you can call $this->geoRepository
}
}
Also note that $this->get() is only a shortcut function provided by the Symfony base Controller class to access the container.
To know more about DI, you can read Fabian's excellent articles about this in his blog .

Creating notifications with Zend Framework 2

I am trying to learn ZF2. I know that there are better methods to create notifications but as I said this is for learning purpose.
My idea is to save the notifications in the database. This is simple I can do it. My question is about how to show them. I have a partial for the header menu , I want to display them there.
I dont know if i am on the right track i currently have a view helper which i create via factory.
class TestMe extends AbstractHelper
{
protected $html;
public function __invoke($name = 'Unnamed')
{
// if($this->view->hasIdentity()){
// $user = $this->view->identity();
// }
//$this->testJS();
return "$name , this is Zend Framework 2 View Helper";
}
protected function htmlIt(){
}
protected function testJS($loggedIn = false){
$js = '';
$js .= <<<JS
alert('test');
JS;
$view = $this->getView();
$view->inlineScript()->prependScript($js);
}
}
I know this is nothing but I cant understand what is good an wrong. My idea is to pass ot the view helper an array with notifications for the user and display them. So I need a service for making calls to the database or there is another way?
ZF2 already has an Notification Helper Plugin. Have a Look at http://framework.zend.com/manual/current/en/modules/zend.view.helpers.flash-messenger.html
But if you really want to do it on your own, you may want to create an Controller Plugin http://framework.zend.com/manual/current/en/modules/zend.mvc.plugins.html.
There is a nice Tutorial for that here: http://lab.empirio.no/custom-controller-plugin-in-zf2.html

Use ZF2 controller plugins for application services within an DDD?

I am currently using DDD (Domain Driven Design) for a new Zend Framework 2 project. Everything works fine but I do have a question regarding the application services.
I understood that application services are located at the application layer and are kind of the entry point to the domain logic. They can access domain services or the repository for example.
I wonder now if it would make sense to implement the application services as controller plugins. In a classical MVC application this controller plugin could handle the results from the called domain services or repositories. Depending on these results they could generate a redirect response or pass data / a form to a ViewModel. If this logic is encapsulated within a plugin my controller only has to call the plugin and return the result of the plugin.
Am I totally wrong about this? Or would you rather keep the logic how to react on results of a domain service or a repository in a controller?
Best Regards,
Ralf
Of course it's kind of subjective and people have strong opinions about things like that... so here's mine:
Controller plugins contain code that's universal to any MVC/REST
action and business logic is not universal. Plugins are supposed to facilitate the
"controlling" of request/response and not the business logic that's
down on the model level. Linking it there would make it less
reusable, e.g. for console actions. Also it'd make it less probable
to use the business logic with some other framework.
It's awkward to test. Injecting controller plugins as controller
class constructor parameters would be kinda redundant, since they are already
available from the plugin manager injected into AbstractActionController or AbstractRestfulController. Not having the dependencies injected in a obivious/visible way (like trough contructor method) makes it harder to figure out what the controller class actually depends
on. Also since all plugins (AbstractPlugin related) depend on controller instance, switching context from
http to console (like for a phpunit test) might get problematic. Also testing logic
written/made available as controller plugin would sooner or later
escalate to including request/response objects in the tests and
that's unnecessary complexity.
It's not intuitive. When I hear plugin I think of something small.
Not a full-blown business logic code buried under such inconspicuous
name. So when I have little time to debug someones code the last
thing I need it to things be out of place like that.
Again I'd like to reiterate, that's just my opinion. I've learned that a lot of patterns can crumble under a weird-enough use case, but the above points made sense to me and my team so far.
As an example for my solution here you can see an controller action:
public function showAction()
{
$service = $this->readProductEntityCommand;
$service->setId($this->params()->fromRoute('id'));
try {
$result = $service->execute();
} catch (ProductException $e) {
$this->flashMessenger()->addMessage($e->getMessage());
return $this->redirect()->toRoute('part3/product');
}
return new ViewModel(
array(
'productEntity' => $result->getData(),
)
);
}
And here is an example of an application service build as an command object
class ReadProductEntityCommand implements CommandInterface
{
protected $productRepository;
protected $id;
public function __construct(ProductRepositoryInterface $productRepository)
{
$this->productRepository = $productRepository;
}
public function setId($id)
{
$this->id = $id;
}
public function execute()
{
if (is_null($this->id)) {
throw new ProductIdInvalidException(
'Produkt ID wurde nicht angegeben.'
);
}
try {
$product = $this->productRepository->getProduct(
new ProductIdCriterion(
new ProductId($this->id)
)
);
} catch (\Exception $e) {
throw new ProductNotFoundException(
'Es konnten kein Produkt gelesen werden.'
);
}
if ($product === false) {
throw new ProductNotFoundException('Produkt wurde nicht gefunden.');
}
$result = new Result();
$result->setValid(true);
$result->setData($product);
$result->setMessage('Produkt wurde gelesen.');
return $result;
}
}
Maybe this helps someone in the future.

ZF2 - BjyAuthorize - How to Get Rules and Guards from a Database

I'm using BjyAuthorize with Zend Framework2 to implement authorization and was able to successfully integrate roles from database. Now I want to get my Rules and Guards also from data base tables. How can I do this?
The easiest method and "the trick" here is really to:
Get your rules and guards into the same array format as it is shown in example configuration. So after reading records from the database, in whatever format your raw database data is, process it to match the same guard format as in the configuration. (My answer goes into detail on how to do that with Doctrine ORM, but also should give you an idea with other DB engines. Just substitute "DB read" operation with your fave database engine)
Inject the rules that are already in the proper format BjyAuthorize expects (because you made them so), into BjyAuthorize\Guard\Controller, from within YOUR_MODULE_NAME\Factory\DoctrineControllerGuardAdapterFactory, which you will write. Bjy's Controller will treat the rules as if those rules came from configuration*, and not suspect any difference.
Step back and enjoy!
This is the construct that you need to write in your own module:
namespace YOUR_MODULE_NAME\Factory;
/**
* See "How and where exactly to register the factory" in ZF2 config
* below in my answer.
*/
class [Custom]ControllerGuardAdapterFactory
{
public function createService(ServiceLocatorInterface $serviceLocator)
{
/**
* Retrieve your rules from favorive DB engine (or anything)
*
* (You may use $serviceLocator to get config for you DB engine)
* (You may use $serviceLocator to get your DB engine)
* (You may use $serviceLocator to get ORM Entity for your DB engine)
* (Or you may hack your DB connection and retrieval in some other way)
*
* Hell, you may read them from a text file using PHP's file() method
* and not use $serviceLocator at all
*
* You may hardcode the rules yourself right here for all that matters
*/
$rules = ... //array(...);
/**
* Inject them into Bjy's Controller
*
* Rules must be in the same format as in Bjy config, or it will puke.
* See how ['guards'][\BjyAuthorize\Guard\Controller::class] is constructed
* in Bjy configuration for an example
*/
return new \BjyAuthorize\Guard\Controller($rules, $serviceLocator);
}
}
Now watch and observe how mind-numbingly complicated this can be made! (modeled after Bjy's own mechanisms)
This is mostly just ZF2, OO & Bjy "Configuration Hell", folks, nothing special otherwise. Welcome to ZF2 and Bjy and ORM Configuration Hell. You are welcome.
Detailed Answer - How to Implement?
Write an adapter factory, which reads rules from database, and then injects them into BjyAuthorize's Controller Guard. The effect will be the same as if the rules were being read from ['guards'][\BjyAuthorize\Guard\Controller::class]
What?
The way BjyAuthorize's Controller Guard works is it takes rules in a certain format (format specified for ['guards']['BjyAuthorize\Guard\Controller']), and then it uses the rules to populate the ACL. It also computes Resources from rules for you and loads those into ACL as well. If it didn't, you would have to write your own Resource Provider to do so.
So the task becomes:
Load rules from database and Transform the rules to format BjyAuthorize expects. This can be done in your own Rule Provider, much like this one.
You can use a factory to load your particular DB and storage class configuration arrays from module.config.php file. I put mine under ['guards']['YOUR_MODULE_NAME_controller_guard_adapter'].
'guards' => array(
'YOUR_MODULE_NAME_controller_guard_adapter' => array(
'object_manager' => 'doctrine.entity_manager.orm_default',
'rule_entity_class' => 'YOUR_MODULE_NAME\Entity\ObjectRepositoryProvider'
)
)
(cont) I put it under guards as opposed to rule_providers, because what we are dealing with here is not a pure rule provider. It is a guard provider, or "an adapter that gets rules out of your ObjectRepositoryProvider, and injects them into controller guard". This factory should look similar to this, except that you will be loading rules, not roles. You will then be injecting the rules into Controller, as in the next step.
Inject the rules into Controller, very much like it is done here
Example Implementation Details (from Q/A in comments)
More on the last point of "Injecting rules into Controller". Basically two steps: 1) make sure you already have (or will) generate your rules somehow (that's the hard step ). 2) inject those rules into controller (that's the easier step). The actual injection is done like this
$rules = __MAGIC__; //get rules out of somewhere, somehow.
return new Controller($rules, $serviceLocator); //$rules injection point
See code block below for my own implementation, where the last line in the block is the line I gave just above here.
namespace YOUR_MODULE_NAME\Factory;
use BjyAuthorize\Exception\InvalidArgumentException;
use Zend\ServiceManager\FactoryInterface;
use Zend\ServiceManager\ServiceLocatorInterface;
use YOUR_MODULE_NAME\Provider\Rule\DoctrineRuleProvider; //this one's your own
use BjyAuthorize\Guard\Controller;
class DoctrineControllerGuardAdapterFactory implements FactoryInterface
{
public function createService(ServiceLocatorInterface $serviceLocator)
{
//just setting up our config, move along move along...
$config = $serviceLocator->get('Config');
$config = $config['bjyauthorize'];
//making sure we have proper entries in our config...
//move along "nothing to see" here....
if (! isset($config['guards']['YOUR_MODULE_NAME_controller_guard_adapter'])) {
throw new InvalidArgumentException(
'Config for "YOUR_MODULE_NAME_controller_guard_adapter" not set'
);
}
//yep all is well we load our own module config here
$providerConfig = $config['guards']['YOUR_MODULE_NAME_controller_guard_adapter'];
//more specific checks on config
if (! isset($providerConfig['rule_entity_class'])) {
throw new InvalidArgumentException('rule_entity_class not set in the YOUR_MODULE_NAME guards config.');
}
if (! isset($providerConfig['object_manager'])) {
throw new InvalidArgumentException('object_manager not set in the YOUR_MODULE_NAME guards config.');
}
/* #var $objectManager \Doctrine\Common\Persistence\ObjectManager */
$objectManager = $serviceLocator->get($providerConfig['object_manager']);
//orp -- object repository provider
//here we get our class that preps the object repository for us
$orp=new DoctrineRuleProvider($objectManager->getRepository($providerConfig['rule_entity_class']));
//here we pull the rules out of that object we've created above
//rules are in the same format BjyAuthorize expects
$rules=$orp->getRules();
//here pass our rules to BjyAuthorize's own Guard Controller.
//It will not know the difference if we got the rules from Config or from Doctrine or elsewhere,
//as long as $rules are in the form it expects.
return new Controller($rules, $serviceLocator);
}
}
DoctrineRuleProvider
namespace YOUR_MODULE_NAME\Provider\Rule;
use Doctrine\Common\Persistence\ObjectRepository;
use BjyAuthorize\Provider\Rule\ProviderInterface;
/**
* Guard provider based on a {#see \Doctrine\Common\Persistence\ObjectRepository}
*/
class DoctrineRuleProvider implements ProviderInterface
{
/**
* #var \Doctrine\Common\Persistence\ObjectRepository
*/
protected $objectRepository;
/**
* #param \Doctrine\Common\Persistence\ObjectRepository $objectRepository
*/
public function __construct(ObjectRepository $objectRepository)
{
$this->objectRepository = $objectRepository;
}
/**
* Here we read rules from DB and put them into an a form that BjyAuthorize's Controller.php understands
*/
public function getRules()
{
//read from object store a set of (role, controller, action)
$result = $this->objectRepository->findAll();
//transform to object BjyAuthorize will understand
$rules = array();
foreach ($result as $key => $rule)
{
$role=$rule->getRole();
$controller=$rule->getController();
$action=$rule->getAction();
if ($action==='all') //action is ommitted
{
$rules[$controller]['roles'][] = $role;
$rules[$controller]['controller'] = array($controller);
}
else
{
$rules[$controller.':'.$action]['roles'][]=$role;
$rules[$controller.':'.$action]['controller']=array($controller);
$rules[$controller.':'.$action]['action']=array($action);
}
}
return array_values($rules);
}
}
Q: How and where exactly to register the factory DoctrineControllerGuardAdapterFactory
A: Try this path: module\YOUR_MODULE_NAME\config\module.config.php and have
'service_manager' => array(
'factories' => array(
'YOUR_MODULE_NAME_controller_guard_adapter' => \YOUR_MODULE_NAME\Factory\DoctrineControllerGuardAdapterFactory::class
)
)
Note: YOUR_MODULE_NAME. The thing on the left of => sign is "the key", and can be anything you want it to be. Convention in Bjy is that it is similar to the actual class names and paths. And the thing on the right of the => is the actual fully qualified namespace to the class that you want to call with with this key.
Basically you have to write your own Provider.
Check out the different RoleProvider. Every RoleProvider implements the Provider\Role\ProviderInterface. The same thing has to be done when you want to implement Guards and Rules. You go into the specific directories Provider\Rule and Provider\Resource and check for the specific ProviderInterface.
That way you can write your own class implementing the Interface and then via configuration you tell BjyAuthorize to use your provider-classes.
As far as Guards are concerned, i do believe it is not yet possible to create those from Database. You would have to modify / PR the Module itself to make that happen.

Resources