I'm new to laravel; i'd like to register an object variable with key "myObject", so that it can be acceded by all users using the current application, and can be acceded in any controller or view. the object can be changed (use a set method) whenever i want. i look for something like ServletContext in JEE or somthing like registry in Zend.
Thanks in advance for you detailed code
You can bind the object into Laravel Service Container as an instance for example, you may create your object instance using something like this:
$object = new SomeClass(...);
App::instance('myObject', $myObject);
In this case, you can bind the object from a service provider. You can use the App\Providers\AppServiceProvider which comes with Laravel. So, in this case, you may do something like this:
// Import the dependencies using "use", omitted here
class AppServiceProvider extends ServiceProvider {
public function boot()
{
// ...
}
public function register()
{
$object = new MyObjectClass();
$this->app->instance('myObject', $object);
// Share the instance globally in all views
view()->share('myObject', $object);
}
}
Later, you can use $object = app('myObject') to get the instance and if you would like to use it in views globally then you may use view()->share('myObject', $object) so you can access the object directly from any view usinf $myObject instance variable. There are other ways to bind an item into the container but this approach meets your need. Check the documentation for more information.
Related
I Can take instance of service using this example:
export class GetEntityDomainService {
constructor(private readonly moduleRef: ModuleRef) { }
getEntity(): void {
const myObject = this.moduleRef.get(MyClassName);
}
}
but how could I invoke a service instance outside of a class object
where I don't have a handle to moduleRef:
here is example from angular:
const injector = ReflectiveInjector.resolveAndCreate(providers);
const widgets: WidgetService = injector.get(WidgetService);
https://kevinphelps.me/blog/2017-01-17-using-angular-dependency-injection-in-node
whether is it possible to download an instance of the service without needing a moduleRef?
Thanks
Piotr
There are several reasons
sometimes I need to inject a service in a function, then I have to pass moduleRef to this function to make it possible
The second example is Command and Events -
for example I create such an action, then I pass parameters to send to handler,:
this.dispach(new Command (parameters ...))
Currently my actions know from which module they are triggered and in which module their handler is - so I won't send actions between wrong areas of the system (layers, dependencies). I check all this when executing
this.dispach (new Command ())
now I have to write such a dispatch as follows:
this.dispach (new Command (this.moduleRef, ... other parameters))
could I create a moduleRef from the code?, it would facilitate the process of creating an action and eliminate the need to pass moduleRef
but I don't know if it will help me
as I analyzed DI nest, it works differently from angular
The service knows where it was declared and when it injects something in it, it uses the tokens declared in this module
I suppose I will only be able to inject general scope
I process messages from a queue. I use data from the incoming message to determine which class to use to process the message; for example origin and type. I would use the combination of origin and type to look up a FQCN and use reflection to instantiate an object to process the message. At the moment these processing objects are all simple POJOs that implement a common interface. Hence I am using a strategy pattern.
The problem I am having is that all my external resources (mostly databases accessed via JPA) are injected (#Inject) and when I create the processing object as described above all these injected objects are null. The only way I know to populate these injected resources is to make each implementation of the interface a managed bean by adding #stateless. This alone does not solve the problem because the injected members are only populated if the class implementing the interface is itself injected (i.e. container managed) as opposed to being created by me.
Here is a made up example (sensitive details changed)
public interface MessageProcessor
{
public void processMessage(String xml);
}
#Stateless
public VisaCreateClient implements MessageProcessor
{
#Inject private DAL db;
…
}
public MasterCardCreateClient implements MessageProcessor…
In the database there is an entry "visa.createclient" = "fqcn.VisaCreateClient", so if the message origin is "Visa" and the type is "Create Client" I can look up the appropriate processing class. If I use reflection to create VisaCreateClient the db variable is always null. Even if I add the #Stateless and use reflection the db variable remains null. It's only when I inject VisaCreateClient will the db variable get populated. Like so:
#Stateless
public QueueReader
{
#Inject VisaCreateClient visaCreateClient;
#Inject MasterCardCreateClient masterCardCreateClient;
#Inject … many more times
private Map<String, MessageProcessor> processors...
private void init()
{
processors.put("visa.createclient", visaCreateClient);
processors.put("mastercard.createclient", masterCardCreateClient);
… many more times
}
}
Now I have dozens of message processors and if I have to inject each implementation then register it in the map I'll end up with dozens of injections. Also, should I add more processors I have to modify the QueueReader class to add the new injections and restart the server; with my old code I merely had to add an entry into the database and deploy the new processor on the class path - didn't even have to restart the server!
I have thought of two ways to resolve this:
Add an init(DAL db, OtherResource or, ...) method to the interface that gets called right after the message processor is created with reflection and pass the required resource. The resource itself was injected into the QueueReader.
Add an argument to the processMessage(String xml, Context context) where Context is just a map of resources that were injected into the QueueReader.
But does this approach mean that I will be using the same instance of the DAL object for every message processor? I believe it would and as long as there is no state involved I believe it is OK - any and all transactions will be started outside of the DAL class.
So my question is will my approach work? What are the risks of doing it that way? Is there a better way to use a strategy pattern to dynamically select an implementation where the implementation needs access to container managed resources?
Thanks for your time.
In a similar problem statement I used an extension to the processor interface to decide which type of data object it can handle. Then you can inject all variants of the handler via instance and simply use a loop:
public interface MessageProcessor
{
public boolean canHandle(String xml);
public void processMessage(String xml);
}
And in your queueReader:
#Inject
private Instance<MessageProcessor> allProcessors;
public void handleMessage(String xml) {
MessageProcessor processor = StreamSupport.stream(allProcessors.spliterator(), false)
.filter(proc -> proc.canHandle(xml))
.findFirst()
.orElseThrow(...);
processor.processMessage(xml);
}
This does not work on a running server, but to add a new processor simply implement and deploy.
I am trying to create a custom manager which is passed in the controller when it is being called and I am having troubles understanding the current implementation of new MVC5 project in c#.
Here is the default implementation:
public AccountController(ApplicationUserManager userManager, ApplicationSignInManager signInManager )
{
UserManager = userManager;
SignInManager = signInManager;
}
above all of that are declarations for them:
public ApplicationSignInManager SignInManager
{
get
{
return _signInManager ?? HttpContext.GetOwinContext().Get<ApplicationSignInManager>();
}
private set
{
_signInManager = value;
}
}
public ApplicationUserManager UserManager
{
get
{
return _userManager ?? HttpContext.GetOwinContext().GetUserManager<ApplicationUserManager>();
}
private set
{
_userManager = value;
}
}
Now from my understanding the SignInManager and UserManager get created when application gets created for the first time in Startup.Auth.cs which looks like this:
app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create);
app.CreatePerOwinContext<ApplicationSignInManager>(ApplicationSignInManager.Create);
So now whenever I call UserManager I will get that first instance that was created when project ran for the first time.
I have 2 questions. Question 1 is is anything I said above wrong and Do I have a wrong understanding of how MVC5 works?
Question2: How is UserManager and SignInManager generated and passed in the controller? Where is the code that creates that first instance of the manager and passes it in the controller? I am assuming it is app.CreatePerOwnContext that does it. If so, can I then just create my own Manager and then register it with Owin in the same fashion and reuse throughout the project? Will my code get the latest data from the database if I do this and not cache it?
The code you're showing is coming from the IMO very ugly MVC5 template, which works out of the box but does some ugly things.
This constructor:
public AccountController(ApplicationUserManager userManager,
ApplicationSignInManager signInManager)
makes you think OWIN automagically injects the managers for you. But in fact this is not the case. That is why the template comes with the ugly properties you supplied in the questions. When you do not change anything to the template, the default constructor is called (also present in the template). To try it, just delete, or comment, the default constructor and you'll see the AccountController can't be created anymore.
So what is actually happening there is that both managers are located using the Service Locator anti pattern in the getters of the supplied properties.
So now whenever I call UserManager I will get that first instance that was created when project ran for the first time?
No this is not the case. What this line:
app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create);
does, is creating a delegate to the Create method of both managers. The managers are cached within an Owin Request. The next request the delegates are called again and you get a fresh ApplicationUserManager etc.
To be a little bit more verbose this line could be rewritten as:
Func<ApplicationUserManager> userManagerFactory = () => ApplicationUserMangager.Create();
app.CreatePerOwinContext<ApplicationUserManager>(userManagerFactory);
So if you would a breakpoint here:
public ApplicationUserManager UserManager
{
get
{
// place breakpoint here
return _userManager ?? HttpContext.GetOwinContext().GetUserManager<ApplicationUserManager>();
}
// ....
You would see that while stepping through the code, you will hit the line where you created the UserManagerFactory which in his turn will call the Create() method of the ApplicationUserManager.
How is UserManager and SignInManager generated and passed in the controller
It isn't! You would need to use dependency injection for that.
If so, can I then just create my own Manager and then register it with Owin in the same fashion and reuse throughout the project
Yes you can. You can completely refactor the ApplicationUserManager you also got 'for free' in the template. As long as you supply a factory method to the 'CreatePerOwinContext' extension method.
Will my code get the latest data from the database if I do this and not cache it?
The instances are cached on per request base. So each request you will get a new one, with a new DbContext etc.
I'm unsure how familiar you are with dependency injection but MVC5 is a pretty easy framework to start with it, IMO.
I once wrote a blogpost how to configure my DI container of choice (Simple Injector) to use with the MVC5 template.
I also wrote several answers here on SO regarding this template: specifically this one, should interest you. This one is interesting also!
I need to get a user provider in a controller in Symfony2.
I've got multiple user_providers, with 1 chain-provider chaining those.
There is a service defined in the container with the name security.user.provider.concrete.XXX (where XXX is what you specified in security.yml), but that service is marked as private.
I've managed to define an alias in the extension class of my bundle:
$container->setAlias('my_bundle.user.provider', new Alias('security.user.provider.concrete.XXX')));
But I rather do it in a more nice way.
So, I got a couple of questions:
Is there a service I can use to fetch a specific user-provider? Which one?
If not, is there a simple way (in a pre-compiler-pass or something) to fetch all user-provider names and simply create Aliases for those services?
I've played with the configuration a little, and figured out how to generically create aliasses for any providers configured using a CompilerPass:
<?php
namespace MyBundle\DependencyInjection\Compiler;
use Symfony\Component\DependencyInjection\Alias;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
class TestCompilerPass implements CompilerPassInterface
{
public function process(ContainerBuilder $container)
{
$securityConfig = $container->getExtensionConfig('security');
foreach ($securityConfig[0]['providers'] as $providerName => $providerConfig) {
$container->setAlias('my_security.provider.' . $providerName, new Alias('security.user.provider.concrete.' . $providerName));
}
}
}
Add the following to your Bundle class:
public function build(ContainerBuilder $container) {
// call parent
parent::build($container);
// run extra compilerPass
$container->addCompilerPass(new TestCompilerPass());
}
This will create an alias for each UserProvider that is present. It will be available under the key: my_security.provider.XXX where XXX is the name configured in your security.yml.
I'm however unsure why the config is prepended with an array with key 0.
I'm also not really sure if this is a good approach. If nothing better comes up I will be using this solution though.
You can get a specific provider by the current loggedin users firewall name:
$token = $this->securityContext->getToken();
$providerKey = $token->getProviderKey(); // secured_area / firewall name
You can get see it here: https://codedump.io/share/unA0SxVxuP9v
I have generated ServiceContext for my CRM organization. I'm able to connect to CRM properly. Since I have all my context configuration in app.config file, I wonder is it possible to get IOrganizationService from already instantiated OrganizationServiceContext?
When I need to access the service reference from multiple places, I usually do it in two steps. First of all I try to see if it's possible to pass it down to the called methods (I'm assuming that you have something like the following).
using (IOrganizationService service
= (IOrganizationService) new OrganizationServiceProxy(...))
{
DoSomething();
DoSomething(service);
}
private void DoSomething(IOrganizationService service) { ... }
When it fails (due to technical setup or just plain dumbness), I set up a private property and in the constructor (or at least the first calling method) assign it a value for future access like this.
class MyClass
{
private IOrganization _service;
private IOrganization _Service
{
get
{
if(_service == null)
_service = (IOrganizationService) new OrganizationServiceProxy(...);
return _service;
}
}
...
}
And if you have a lot of code that operates on the server, you might want to move all that stuff to a separate class and have the calls made to it (with the property setup discussed above).
I'm not fully sure if I got your question correctly so be nice if I'm missing your point.