Ember. Inject an addon service into additional 'areas' - service

How would I inject an addon service into other 'places'?
For example, if I install an addon that injects into controllers & components with the code below:
export default {
name: 'notification-messages-service',
initialize() {
let application = arguments[1] || arguments[0];
application.register('notification-messages:service', NotificationMessagesService);
['controller', 'component'].forEach(injectionTarget => {
application.inject(injectionTarget, 'notifications', 'notification-messages:service');
});
}};
How would I then inject the same service (the same singleton) into services & routes - my requirement is actually inject into a single service, services:messages?
I don't believe I can use
notifications: Ember.inject.service();
because in the addon the service is written as:
export default Ember.ArrayProxy.extend({...});
I can change the addon, of course, but my changes would be gone once the addon is updated.
Thanks for looking, N

notifications: Ember.inject.service('notification-messages');
should work
param for service is optional if name of service the same as property name, but it's bette always use it
P.S. code above for normal services
in you case code
['controller', 'component'].forEach(injectionTarget => {
application.inject(injectionTarget, 'notifications', 'notification-messages:service');
});
means that controllers/components just get new property notifications
So inside your controllers/components you can use
this.get('notifications')

I was able to inject the addon to my specific service by creating a new initialiser with the code below:
export default {
name: 'inject-ember-notification-service',
initialize: function(container, app) {
app.inject('services:message', 'notifications', 'notification-messages:service');
}
};
Fiendishly obtuse, ember!
Thanks to you all for your input.

Related

How can I make a symfony 4 command to be registered only in dev environment and disabled in prod?

In my App I have a helper class App\Command\GenerateFixturesCommand that provides a command named my-nice-project:generate-fixtures.
This command consumes a service of my own project named App\Services\CatalogFixtureGenerator that generates 1000 random PDF documents for testing while developing the app.
To do so, this service uses the joshtronic\LoremIpsum class which is required in composer only in dev. LoremIpsum is a third-party library. I require it under composer's require-dev.
So the injection is:
I run my GenerateFixturesCommand.
Before that, the system transparently locates my CatalogFixtureGenerator and to inject it into the command.
Before that, the system transparently locates the LoremIpsum third party service to inject it into my fixture generator service.
All is autowired.
When I deploy to prod and do composer install --no-dev --optimize-autoloader of course the LoremIpsum class is not installed.
But when I clear the cache with APP_ENV=prod php bin/console cache:clear the framework finds the command and cannot inject the autowired dependencies.
[WARNING] Some commands could not be registered:
In CatalogsFixtureGenerator.php line 26:
Class 'joshtronic\LoremIpsum' not found
This my-nice-project:generate-fixtures command is never going to be used in the production server.
Question
How can I "disable" the command in prod?
I mean: How can I tell the framework that the class GenerateFixturesCommand should not be loaded nor its autowired dependencies, and neither of them should be autowired in prod?
Use the isEnabled() method in Command.
For example
public function isEnabled(): bool
{
// disable on prod
if ($this->appKernel->getEnvironment() === 'prod') {
return false;
}
return true;
}
In my last project, I need some commands to work only in dev environment. You use getenv function to achieve this:
# src/Command/SomeCommand.php
...
public function __construct()
{
parent::__construct();
if (getenv("APP_ENV") !== "dev") {
exit('This command should work only "dev" environment.');
}
}
This will do the trick.
Code fun :)
The solution #gusDeCooL suggests doesn't work with lazy-loaded commands (at least not for me).
I ended up implementing the isEnabled() method anyway, but then I added a guard in execute():
<?php
namespace App\Command;
use Symfony\Component\Console\Attribute\AsCommand;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;
#[AsCommand(
name: 'command:name',
description: 'Some description',
)]
class CommandName extends Command
{
public function isEnabled(): bool
{
return 'dev' === getenv('APP_ENV');
}
protected function execute(InputInterface $input, OutputInterface $output): int
{
$io = new SymfonyStyle($input, $output);
if (!$this->isEnabled()) {
$io->error('This command is only available in `dev` environment.');
exit(1);
}
// the rest
}
}

Service Fabric Stateful Service Remoting V2

I have a Stateful Service called by a Stateless service, in .Net Standard Asp.net Core 2.0 running on Visual Studio 15.4.
I can't make the Service Remoting V2 work.
The old code in the Stateful service that worked for V1 is not valid anymore
protected override IEnumerable<ServiceReplicaListener> CreateServiceReplicaListeners()
{
return new List<ServiceReplicaListener>()
{
new ServiceReplicaListener((context) =>this.CreateServiceRemotingListener(context))
};
I tried to follow this tutorial but the example is for the stateless one.
I tried to change the code in this without success.
protected override IEnumerable<ServiceReplicaListener> CreateServiceReplicaListeners()
{
return new List<ServiceReplicaListener>()
{
new ServiceReplicaListener((c) =>new FabricTransportServiceRemotingListener(c, this))
};
}
Also there are no instructions on how or where to use this code in the tutorial
var proxyFactory = new ServiceProxyFactory((c) =>
{
return new FabricTransportServiceRemotingClientFactory();
});
I'm stuck, could someone show me how to make it work?
In your stateful service, in method CreateServiceReplicaListeners, use this code:
protected override IEnumerable<ServiceReplicaListener> CreateServiceReplicaListeners()
{
return this.CreateServiceRemotingReplicaListeners();
}
And in the file that defines your remoting service interface, add this:
[assembly: FabricTransportServiceRemotingProvider(RemotingListener = RemotingListener.V2Listener, RemotingClient = RemotingClient.V2Client)]
(for example, just below the using namespaces list.)
Add the endpoint:
<Endpoint Name="ServiceEndpointV2" />
And rebuild the client.

call a global constant into service Angular2

In my Angular2 application I use services which call a REST API like this from http://localhost:22222/app/webresources/entity..
I want to set part of this URL just one time and call it from the services which I need.
I think I need to create an Interface which has a constant URL, but is it possible to implement this in a service?
I put something like this in my data-access.service.ts:
export const API_URL: string = "http://my.api.com/"
It's useful because I can use it in my service methods:
getStuff(): Observable<Stuff> {
return this.http.get(API_URL + `/path/to/stuff/with/${parameters}`)
.map(response => response.json())
.catch(this.logError);
Or later in a template somewhere:
import { API_URL } from '../shared/data-access.service';
#Component({
template: 'Link to stuff'
})
export class MyComponent {
api: string = API_URL;
…
}

Custom Session interfering with acceptance tests

I am using ember-cli-simple-auth and ember-cli-simple-auth-devise in an ember-cli project.
I'm also customizing simple-auth's Session via an initializer:
// app/initializers/custom-session.js
import Ember from 'ember';
import Session from 'simple-auth/session';
export default {
name: 'custom-session',
before: 'simple-auth',
initialize: function(container, application) {
Session.reopen({
setCurrentUser: function() {
var id = this.get('user_id'),
self = this;
if (!Ember.isEmpty(id)) {
return container.lookup('store:main').find('user', id)
.then(function(user) {
self.set('currentUser', user);
});
}
}.observes('user_id')
});
}
};
In a simple acceptance test (one that simply calls ok(1)), I'm getting the following error
Error: Assertion Failed: calling set on destroyed object
Source:
at Adapter.extend.exception (localhost:4900/assets/vendor.js:57907:19)
at apply (http://localhost:4900/assets/vendor.js:21143:27)
at superWrapper [as exception] (localhost:4900/assets/vendor.js:20721:15)
at RSVP.onerrorDefault (localhost:4900/assets/vendor.js:59827:26)
at Object.__exports__.default.trigger (localhost:4900/assets/vendor.js:22673:13)
at Promise._onerror (localhost:4900/assets/vendor.js:23397:16)
at publishRejection (localhost:4900/assets/vendor.js:23804:17)
at http://localhost:4900/assets/vendor.js:29217:9
If I comment out the self.set('currentUser', user); line, the error goes away.
What's the appropriate way to handle this? Is there a way to ignore this initializer in tests?
I also get this log message:
No authorizer factory was configured for Ember Simple Auth - specify one if backend requests need to be authorized.
First of all you should update Ember Simple Auth to the latest version 0.6.4 that allows you to specify a custom session class without having to reopen the default Session: https://github.com/simplabs/ember-simple-auth/releases/tag/0.6.4.
Secondly, the warning about the authorizer simply means that requests going to a backend server will not be authorized (e.g. will not have an Authorization header) as no authorizer is defined. That might be ok though depending on your setup.
Regarding the destroyed object problem you could simply check whether the object is destroyed:
if (!self.isDestroyed) {
self.set('currentUser', user);
}

How to resolve with a default class if a matching register is not found in Autofac

I am using the following code for register:
builder.RegisterType<QCatVCardParser>().Named<IQCatParser>(".VCF");
builder.RegisterType<QCatVCardParser>().Named<IQCatParser>(".VCARD");
builder.RegisterType<QCatOutlookMessageParser>().Named<IQCatParser>(".MSG");
builder.RegisterType<QCatMimeMessageParser>().Named<IQCatParser>(".EML");
builder.RegisterType<QCatCalendarParser>().Named<IQCatParser>(".ICS");
container = builder.Build();
To retrieve a class reference I am using the below code:
var r = container
.ResolveNamed<IQCatParser>(Path.GetExtension(fileName).ToUpperInvariant());
Now my question is if a unsuppoted file extension comes let's say .DOC I want to resolve it with a component among one of the registered classes or else with the first registered class.
Is it possible to do this with AutoFac?
You can do this with Autofac. You need to create an IRegistrationSource that can provide the default registration if needed. For example, here is the RegistrationsFor code of a source that provides settings classes:
var typedService = service as IServiceWithType;
if (typedService != null && typedService.ServiceType.IsClass && typeof(ISettings).IsAssignableFrom(typedService.ServiceType))
{
yield return RegistrationBuilder.ForDelegate((c, p) => c.Resolve<ISettingsReader>().Load(typedService.ServiceType))
.As(typedService.ServiceType)
.CreateRegistration();
}
Then, inside of a module or directly using your Autofac builder, call RegisterSource to hook up the new registration source.