I know Ember has a logger, but I wanted to create my own for learning purposes. I have a service called logger, and I want to be able to use this service everywhere. I have no problem injecting this service into components, controllers, and etc... I cannot figure out how to inject this service into a Utility I created without passing it through the create function. I don't want to have to pass my logger everywhere I create the utility. When I try to inject it into the object it complains about not being in a container. What's the best way to do this?
Okay, its important to understand what Ember.inject.service actually does! Its like a shorter version for this:
myService: Ember.computed({
get() {
return Ember.getOwner(this).lookup('service:myService);
}
}),
So what is this getOwner? It gives you the owner of an Object. Most of your objects like models, controllers, components, views and so on are created by the Dependency Injection (DI) container. For a class to be available on the DI container it needs to be registered.
Your default classes like controllers, routes, views are automatically registered by the Resolver. After registration you can inject them into other classes automatically when they are created by the container. Also into all instances created by the container the owner is injected.
Because the container itself is private, these public APIs are on the Application. getOwner also returns the application.
If you want to manually lookup an instance on the container you can use lookup.
For your utility class you probably use a normal .create() to get the object. This of course will not automatically couple it to your application, so the owner is not available. Also automatic injection will not work.
You can manually inject the owner with the ownerInjection:
myClass.create(Ember.getOwner(this).ownerInjection(), {...});
Then Ember.inject.service will work because getOwner will return the injected owner.
The other thing you could do is to register your utility objects on the container and then look them up. Then the owner is automatically injected.
Not sure which Ember version initiated this pattern but the Ember documentation contains the answer to that question starting from v4.3:
import { inject as service } from '#ember/service';
import { getOwner, setOwner } from '#ember/application';
class Item {
#service('shopping-cart') cart;
constructor(context) {
setOwner(this, getOwner(context));
}
function addToCart() {
this.cart.add(this);
}
}
// On any framework object...
let item = new Item(this);
item.addToCart();
I hit a similar problem a little while back.
The utilities are of type Ember.Object.
So, all you have to do is inject the service into the Ember.Object class as a property.
Like this:
Ember.Object.reopen({
testService:Ember.inject.service('testService')
});
Et Voila!Now you can literally use your service anywhere
Related
Perhaps this is a little esoteric but I need some help.
My use case is a clock ticker. I want a service that upon init() will start a timer. (for example an AJAX polling service). I want this to start at app boot but I don't wish to inject it into every object type.
What I've tried:
Writing a service and using Ember.inject.service() in the application controller.
Use an initializer with app.register(…, MyService.create(), {instantiate: false}) without calling app.inject(…).
Don't start the timer in the init() instead Ember.inject.service() it into the application route/controller and in its init() call this.get('myService').startTimer().
Here are some of the stumbling blocks I've run into:
Services are lazy loaded and so the timer never starts because the application controller never performed a this.get('myService'). I could do that in the controller's init() but that felt like a code smell.
Seems that the ember resolver will see the services/my-service.js file and auto register it. Performing an app.register() seems to register two instances and the two get confused.
Like getting the lazy service in the application controller's init() this solution also felt like a code smell. But of all the solutions I've tried this works and is the least smelly of the three.
Is there any other alternatives?
TL;DR Use an instance initializer
An instance initializer will have the needed lookup functions to fetch a service that the system auto registered and perform an action on it.
However, it may be more appropriate to save this initialization for a route or controller's init() because any ajax like thing here will still fall under Embers Loading state and run loop. While being performed in an instance initializer will degrade boot performance with no actual benefits.
If you still feel the initializer is the way to go here is a contrived example that is both Ember 1.13 and 2.0 compatible:
// app/instance-initializers/start-my-service.js
export function initialize(app) {
const { container = app } = app;
const myService = container.lookup('service:my-service');
myService.startPolling();
}
export default {
initialize
};
An example ember-twiddle.
I understand the benefit or repository pattern but I just can't understand in Symfony3 Doctrine there are Doctrine\ORM\EntityManager and \Doctrine\ORM\EntityRepository
What are the difference between the two?
Is repository should be injected to controller or entity manager?
Edit
The correct question should be: What's the proper way to access a repository from a controller?
Should a repository be injected to a controller as a service?
Should a repository be injected to another service as a service?
Should entity manager contain any query at all?
Edit
The correct question should be: should a service contain a query at all? Which #MateuszSip already explained, it could be done by injecting Entity Manager
Should a custom function like getAvailableManagers be put in
repository or services? (Where manager is a repository and there
are some logic in determining available manager)
How about a more generic function like findAllManager, should it be in repository or entity manager?
Currently I'm using Symfony3. Thank you very much
Cheers,
Edit
Talking to #MateuszSip (thanks mate), I decided to make my question clearer with an example below. Please note that below code are not representing real problem
controller
Class ManagementController
{
public function assignManager($projectType)
{
// Grabbing a service
$s = $this->get('mycompany_management_management_service')
$managers = $s->findAvailableManagers();
$managers = $s->checkCapability($managers, $projectType);
return $managers
}
}
repository
class ManagerRepository extends \Doctrine\ORM\EntityRepository
{
public function findAvailableManagers()
{
...
return $managers
}
public function checkCapability($managers, $type)
{
...
return $capableManagers
}
}
services
class ManagementService
{
... I am not sure what should be here.
}
EntityManager is used to manage doctrine-related objects, so:
you can persist an entity object (it's now managed by doctrine, and ready to save)
you can remove an entity object (so it'll be deleted later)
you can flush, and it'll trigger pending operations
you can get a repository (to get objects you'll need) or use a generic api to get an object by a primary key
etc.
It's a class that manages a state of objects and their relation to the database.
Repository is a pattern that standarizes an access to the entites.
If your app is complex, you should inject a separate service(s) to your controller. So there's a UserSaver service (as an example) that use entityManager to create/update a user and UserFinder (or something well-named) using UserRepository which's responsible of fetching user by defined criterias.
You can create a query using entity manager, but em itself cannot contain queries.
In my opinion, define a method inside a service, and a corresponding method in your UserRepository. At this moment, all of what you want should be fetched by a database, but it can change later.
In repository. Methods like: findByRole(role=manager), findIsActive, findOneBySecurityNumber relies to a repository.
I'm trying to inject an Ember service into an Ember Object but keep getting the following error:
"Assertion Failed: Attempting to lookup an injected property on an
object without a container, ensure that the object was instantiated
via a container."
My code looks essentially something like the following:
const Model = Ember.Object.extend({
store: Ember.inject.service(),
destroyRecord() {...},
serialize() {...},
deserialize() {...},
});
let newModel = Model.create();
newModel.get('store');
Note: it does work if I inject the service into a Controller, but not an object. Haven't had any luck trying to figure out how to register the Object with the Ember container.
It works for an Ember.Controller because Ember controls the lifecycle of the object. In short, when Ember needs an instance of a certain controller, it asks the container for one, and the container will provide the instance, initializing if necessary.
What this implies is that for dependency injection to work, you would need to get a new instance of Model through the container. Assuming Ember 2.3 because of getOwner, and that this is somewhere inside the Ember application:
let owner = Ember.getOwner(this);
let newModel = owner.lookup('object:model');
newmodel.get('store');
You can consult the lookup documentation here.
But how to register? Use an application initializer:
$ ember generate initializer register-model
Then, open up the generated initializer and, assuming that your file is in app/folder/model.js, put something like:
import Model from 'app-name/folder/model';
export function initialize(application) {
application.register('object:model', Model);
}
export default {
name: 'register-model',
initialize
};
You can consult the register documentation here.
Hope this is helpful!
Well you need to passing in the container instance when you create a instance of your model. The container is accessible in the route, controllers, components with this.get('controller'). AFAIK basically anything created with the container gets the container property set. Thats why service injections work in controllers etc..
So if you are creating the model in a route's method. The code will look like below
App.IndexRoute = Ember.Route.extend({
model: function() {
var newModel = Model.create({
container: this.get('container')
});
return newModel.get('test').getText();
}
});
Here is a working demo.
I want to create a LinkedinApi class, containing functions which execute web service requests to Linkedin servers. These functions need to be accessible from anywhere in the Play app code. The easiest way I've written such API classes in the past, was to have them declared as an object. Then LinkedinApi.myPublicFunction() is available from anywhere.
The problem is that I don't see how I can declare my LinkedinApi class as an object. It would use Play 2.4's web services, and this is done by adding #Inject()(ws: WSClient) to the class declaration. Something like object LinkedinApi #Inject()(ws: WSClient) extends Controller.
The problem is that the line above doesn't compile. It seems that #Inject can only be used with class declarations, not with object.
So how can I create application-wide API functions which perform web service calls?
I think you should define your LinkedinApi as a service and inject it where needed:
#Singleton
class LinkedinApi #Inject()(ws: WSClient) {
//...
//linkedin stuff
//...
}
and inject as:
#Singleton
class SomeController #Inject()(linkedinApi:LinkedinApi) {
//...
}
I'm having trouble using Moq in a UnitTesting project with Ninject.
First a few lines about my solution. It contains several projects (BussinesLogic, DAL, Infrastructure...). My goal is to UnitTest the logic i'm using in BussinessLogic project.
The solution is basicly for a windows service, but i've put in the logic so it can be run standalone. I'm using Ninject and i specify weather i want to use the ProductionModule or the TestingModule (windows service uses ProductionModule, console app uses TestingModule)
I'm using a factory pattern to get ninject kernel whenever i need it inside my application.
My TestingModule inherits from NinjectModule where i override the Load() method and there i do the binding. For instance:
Bind<IStorageManager>().To<StubStorageManager>();
I have the StubStorageManager but it's empty. It contains just the declaration of methods from IStorageManager.
The thing i would like to do is (in laymans terms):
Create a unitTest where i would create a new kernel specifying the TestingModule as it's parameter. Then i would like to create a mock object (let's say a mock of IStorageManager) storageManagerMock. Some method in IStorageManager returns a messageObject so i would probably need to mock that too, couse the bussiness logic is doing something based on that messageObject. So i would like to somehow set properties to that message object and then call some businessLogic method on it, so i can see if the logic works correctly.
I hope i didn't complicate it too much.
Please bear with me, i'm completely new to mocking and dependency injection, but am willing to learn.
I doubt you really want to be using Ninject in your tests. The whole point of using ninject is that you can decouple everything. You also want to try and keep everything decoupled from the dependency container itself if possible. Pass it in if you have to, or pass in factories that create the required object and have the container pass in the factory.
I suspect you probably want to do something like this:
public void ATest(){
//create a mock StorageManager
var managerMock = new Mock<IStorageManager>();
//create a mock MessageObject to be used by business logic
var messageObjectMock = new Mock<MessageObject>();
//have the storage manager return the mock message when required
managerMock.Setup(x => x.GetMessageObject()).Returns(messageObjectMock.Object);
//set up message expectations
messageObjectMock.Setup(x => x.ThisValueExpected).Returns(10);
messageObjectMock.Setup(x => x.ThisFunctionShouldBeCalled()).Verifiable("Function not called.");
//thing to test
BusinessLogicObject blo = new BusinessLogicObject(managerMock.Object);
blo.DoTheThingImTesting();
//make sure the business logic called the expected function, or do whatever check you need...
messageObjectMock.Verify();
}