Can't inject repository on some controller Typo3 - dependency-injection

In my custom controller, i'm trying to inject a repository as a dependecy, like this
class FundedProjectController extends ActionController {
/**
* #var \GeorgRinger\News\Domain\Repository\NewsRepository
*/
protected $newsRepository;
/**
* Inject a news repository to enable DI
*
* #param \GeorgRinger\News\Domain\Repository\NewsRepository $newsRepository
*/
public function injectNewsRepository(\GeorgRinger\News\Domain\Repository\NewsRepository $newsRepository)
{
$this->newsRepository = $newsRepository;
}
...
But when I call it in my previewAction, i have an error saying that my $this->newsRepository is null.
But this injection is working on this controller, but I can't figure out why...
class NewsController extends NewsBaseController
I'm working on 7.6.32, stagging website but production mode enable, all caches cleared (also tried with ?no_cache=1, also tried with "#inject"

TYPO3 now requires to configure dependency injection. It does not work automatically any more. Basically you need to add a special Configuration/Services.yaml file. See here how to configure it.

Related

TYPO3 how to inject objectManager in hook?

Maybe it's just simple, but I can't figure it out.
TYPO3 8.7: I am programming a small hook: if a certain condition is met I want to send an email. Therefore I need the standalone view for the email template. But for the standalone view I need the object manager:
/** #var \TYPO3\CMS\Fluid\View\StandaloneView $emailView
$emailView = $this->objectManager->get('TYPO3\\CMS\\Fluid\\View\\StandaloneView');
At the beginning of my class I tried to inject the objectManager:
/**
* #var \TYPO3\CMS\Extbase\Object\ObjectManagerInterface
*/
protected $objectManager;
/**
* #param \TYPO3\CMS\Extbase\Object\ObjectManagerInterface $objectManager
* #internal
*/
public function injectObjectManager(\TYPO3\CMS\Extbase\Object\ObjectManagerInterface $objectManager)
{
$this->objectManager = $objectManager;
}
But it does not work: I run into an error: the objectManager is a null object. Which obviously means that the injection mechanism is not present in the hook.
How can this be achieved then?
Extbase Dependency Injection is not available in hooks, so you have to create instances of objects yourself.
$standaloneView = GeneralUtility::makeInstance(\TYPO3\CMS\Extbase\Object\ObjectManager::class)
->get(TYPO3\CMS\Fluid\View\StandaloneView::class);

StructureMap: How to send the container to a class that has a Constructor that does not accept Parameters

I am trying to find out how I can pass the StructrueMap container to a class that I wrote that inherits from another (MS-Class).
namespace TheNamespace
{
public class DatabaseIssuerNameRegistry : ValidatingIssuerNameRegistry
{
/* **This can't be done**
public DatabaseIssuerNameRegistry(IPortalTenantManager portalTenantManager)
{
_someField= portalTenantManager;
}*/
protected override bool IsThumbprintValid(string thumbprint, string issuer)
{
//How does it work ???????????
var portalTenantManager = container.GetInstance<IPortalTenantManager>();
//Do something with the portalTenantManager
}
}
I need portalTenantManager to be the Instance that I have defined in my container in the Global.asax.
My Global Assax has these things setup:
protected void Application_Start()
{
var container = new Container();
container.Configure(x =>
{ ....
....
x.For<IPortalTenantManager>().Use<PortalTenantManager>();
});
...
...
ControllerBuilder.Current.SetControllerFactory(new StructureMapControllerFactory(container));
...
GlobalConfiguration.Configuration.DependencyResolver = new StructureMapApiControllerFactory(container);
...
}
Edit:
Because of the comments of #NightOwl888 I'll explain a bit further what this class does. (Hopefully explaining so why my hands are tied)
My application is able to authenticate a user with Azure Active Directory and is Multi-tenant capable. In the authentication pipeline I have the possibility to store the validation endpoints in my database instead of the default way on the web.config file. See MSDN
and this, which actually is explaining exactly what I'm doing.
So I registered my class in the web.config under the Tag issuerNameRegistry. At some point of the validation pipeline my class is instantiated and the overriden method IsThumbprintValid is beeing called. The problem is that the class registered in issuerNameRegistry expects a parameterless constructor (there it is! the constrained construction!), therefore I cannot create a constructor that would solve my problem.
Thanks for your help
It turns out that this question has been asked before on MSDN, the answer of which was provided by Travis Spencer in 2 different posts.
it is typical in my experience to have a single container and use that service- or Web-side-wide. In the startup of the service or Web app, you can create the container, register the dependencies, new up an instance of your SecurityTokenServiceConfiguration class, resolve your dependencies, use it to punch out a SecurityTokenService object, and host it.
After the first beta, we really pushed for DI support. We got a little hook in beta 2. You can now create a custom SecurityTokenServiceConfiguration class that overrides the virtual CreateSecurityTokenService method. The implementation in Microsoft's SecurityTokenServiceConfiguration does Activator.CreateInstance; yours can do IoC. This can include the resolution of an IssuerNameRegistiry. Something like this perhaps:
RequestSecurityTokenResponse Issue(IClaimsPrincipal principal, RequestSecurityToken request)
{
SecurityTokenServiceConfiguration config = new MyGoodSecurityTokenServiceConfiguration();
SecurityTokenService sts = config.CreateSecurityTokenService();
RequestSecurityTokenResponse rstr = sts.Issue(principal, request);
return rstr;
}
public class MyGoodSecurityTokenServiceConfiguration : SecurityTokenServiceConfiguration
{
public override SecurityTokenService CreateSecurityTokenService()
{
IssuerNameRegistry = IoC.Resolve<IssuerNameRegistry>();
var sts = IoC.Reslove<SecurityTokenService>();
return sts;
}
}
Of course, this means that you need to create a static instance of your DI container so it is accessible to your SecurityTokenServiceConfiguration class. Personally, I don't like that idea because it makes your DI container accessible throughout the application, which can lead to abuse of the DI container as a service locator.
Ideally, there would be a way in any DI friendly framework to pass the container into an abstract factory in order to resolve service dependencies. However, since I am not familiar with WIF it is unclear whether that can be done - perhaps the class where the Issue method exists could have a constructor added? The trick is to keep walking up the chain until you find the first place in the framework where you can intervene and do all of your DI configuration there.

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.

How do I include or autoload external libraries in a TYPO3 Extbase Extension? + Dependecy Injection?

I'm developing a TYPO3 4.6 Extension with Extbase 1.4 and im trying to include an external library. The library, in my case the facebook PHP SDK, is under $_EXTKEY/Resources/PHP/facebook-php-sdk/facebook.php. I would like the library to autoload and automatically inject (Dependecy Injection) where I need it.
Some comments I found online suggest that one should include libraries with require_once():
http://forge.typo3.org/issues/33142
if it's just a tiny helper library, it's intended to be stored in {PackageRoot}/Resources/PHP/{libraryName} and just included via require. is this suspected by the problem however?
if the FLOW3 package mainly represents the foreing library at all, like it's the case in Imagine or Swift package, the library code is put below {PackageRoot}/Classes directly."
http://lists.typo3.org/pipermail/typo3-project-typo3v4mvc/2011-July/009946.html
"I would include the class (using require_once) from within a specific action to handle this. That way you have access over those functions and the class becomes your library."
I tried this and it works like this:
<?php
require_once( t3lib_extMgm::extPath('extkey') . 'Resources/PHP/facebook-php-sdk/facebook.php');
class Tx_WsLogin_Domain_Repository_FacebookUserRepository extends Tx_WsLogin_Domain_Repository_UserRepository {
protected $facebook;
public function __construct() {
$this->setFacebook(new Facebook(array(
'appId' =>'',
'secret' => '')
));
parent::__construct();
}
public function setFacebook(Facebook $facebook) {
$this->facebook = $facebook;
}
public function sampleFunction() {
$userId = $this->facebook->getUser();
}
}
?>
But how can I get it to autoload and automatically inject the library with the injectFacebook function?
edit:
Like #alex_schnitzler and #sorenmalling mentioned about autoloading:
#PeterTheOne Put all the files inside ext_autoload.php and then use DI or the object manager.
#PeterTheOne put the class definition into ext_autoload.php in your extension?
I tried it like this (file: ext_autoload.php):
<?php
$extPath = t3lib_extMgm::extPath('extKey');
return array(
'facebook' => $extPath . 'Resources/PHP/facebook-php-sdk/facebook.php',
);
?>
It seems to find and include the right file. But when I try to user Dependency Injection (like peter answered) I get an error:
not a correct info array of constructor dependencies was passed!
InvalidArgumentException thrown in file /var/syscp/webs/web1/dev/typo3_src-4.5.15/typo3/sysext/extbase/Classes/Object/Container/Container.php in line 247.
I think this is because the constructor of the Facebook class has a required $config argument.
edit2:
I did what peter said in his answer and with the help of #alex_schnitzler and #sorenmalling, who pointed me to the ObjectManager, my FacebookService looks like this now:
class Tx_Extkey_Service_FacebookService implements t3lib_Singleton {
/**
* #var Tx_Extbase_Object_ObjectManagerInterface
*/
protected $objectManager;
/**
* Facebook from #link https://github.com/facebook/facebook-php-sdk facebook-php-sdk
*
* #var Facebook
*/
protected $facebook;
/**
* #param Tx_Extbase_Object_ObjectManagerInterface $objectManager
*/
public function injectObjectManager(Tx_Extbase_Object_ObjectManagerInterface $objectManager) {
$this->objectManager = $objectManager;
}
/**
*
*/
public function initializeObject() {
$this->facebook = $this->objectManager->create(
'Facebook',
array(
'appId' =>'input appId here',
'secret' => 'input app secret here'
)
);
}
/**
* #return Facebook
*/
public function getFacebook() {
return $this->facebook;
}
}
For more help read: http://forge.typo3.org/projects/typo3v4-mvc/wiki/Dependency_Injection_(DI) the parts about initializeObject() and Creating Prototype Objects through the Object Manager
First create ext_autoload.php in extension root folder
and add your code,it contain single dimension array with key as class name(class name must be prefix with extension key) and value as path to file.
make sure clear your site
<?php
$extensionPath = \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::extPath('rent_system');
return array(
'rent_system_TCPDF' => $extensionPath.'Resources/Private/PHP/tcpdf/tcpdf.php',
);
?>
In controller file
$pdf = $this->objectManager->create('rent_system_TCPDF');
Extbase injection is pretty simple. Here's the actual implementation. Using external libraries, however, is not.
Once you figure out how to load the library, have you tried just injecting it? Like so:
/**
* #var Facebook
*/
protected $facebook;
/**
* inject the facebook
*
* #param Facebook facebook
* #return void
*/
public function injectFacebook(Facebook $facebook) {
$this->facebook = $facebook;
}
NOTE: You need the #param in the comment and you also need to clear your configuration cache after adding this code.
I don't know about the Facebook SDK API, but hopefully you can instantiate the Facebook object with the default constructor and then add the arguments later with setter methods. You might want to create a FacebookService class (singleton) that loads the Facebook PHP and sets the essential arguments. Then you can inject a FacebookService to get the actual Facebook object whenever you need it.

Add setter injection to an existing service

I want to add a setter injection to an existing service. The base service is defined as follow:
[container] Information for service doctrine.orm.default_entity_manager
Service Id doctrine.orm.default_entity_manager
Class Doctrine\ORM\EntityManager
Tags -
Scope container
Public yes
I have overridden the class parameter of the service in the config.yml file to use my own class which add a setExample() method to the base class. The service definition now looks like:
[container] Information for service doctrine.orm.default_entity_manager
Service Id doctrine.orm.default_entity_manager
Class MyCustom\EntityManager
Tags -
Scope container
Public yes
How can I modify/override this service configuration to add my own setter injection in my own services.yml file ?
What I would do is use the extension class in your bundle DependencyInjection namespace. It should be something like:
<?php
namespace YourNamespace\YourBundle\DependencyInjection;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\Config\FileLocator;
use Symfony\Component\HttpKernel\DependencyInjection\Extension;
use Symfony\Component\DependencyInjection\Loader;
use Symfony\Component\DependencyInjection\Definition;
/**
* Provide a DIC extension to support configurable cheeta subscription adapters.
*/
class YourNamespaceYourBundleExtension extends Extension
{
/**
* {#inheritDoc}
*/
public function load( array $configs, ContainerBuilder $container )
{
// Some stuff with configuration...
$configuration = new Configuration();
$config = $this->processConfiguration( $configuration, $configs );
// Load service configuration
$loader = new Loader\XmlFileLoader( $container, new FileLocator(__DIR__.'/../Resources/config' ) );
$loader->load( 'services.xml' );
$container->findDefinition('doctrine.orm.default_entity_manager')->addMethodCall('setExample', array(/* Eventual parameters */));
}
}
There is probably also a way to do the same using service inheritance, but I never tried. In the Extension class however you can do the same things you do in the service.xml file plus use php logic and semantic configuration to do more advanced stuffs.

Resources