-
-
Notifications
You must be signed in to change notification settings - Fork 4.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[FEATURE ember-container-inject-owner]: Inject owner
instead of container
during lookup
.
#11874
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,8 @@ | ||
import Ember from 'ember-metal/core'; | ||
import { assert } from 'ember-metal/debug'; | ||
import dictionary from 'ember-metal/dictionary'; | ||
import isEnabled from 'ember-metal/features'; | ||
import { setOwner } from './owner'; | ||
|
||
/** | ||
A container used to instantiate and cache objects. | ||
|
@@ -17,12 +19,20 @@ import dictionary from 'ember-metal/dictionary'; | |
*/ | ||
function Container(registry, options) { | ||
this.registry = registry; | ||
this.owner = options && options.owner ? options.owner : null; | ||
this.cache = dictionary(options && options.cache ? options.cache : null); | ||
this.factoryCache = dictionary(options && options.factoryCache ? options.factoryCache : null); | ||
this.validationCache = dictionary(options && options.validationCache ? options.validationCache : null); | ||
} | ||
|
||
Container.prototype = { | ||
/** | ||
@private | ||
@property owner | ||
@type Object | ||
*/ | ||
owner: null, | ||
|
||
/** | ||
@private | ||
@property registry | ||
|
@@ -232,6 +242,11 @@ function factoryFor(container, fullName) { | |
factoryInjections._toString = registry.makeToString(factory, fullName); | ||
|
||
var injectedFactory = factory.extend(injections); | ||
|
||
if (isEnabled('ember-container-inject-owner')) { | ||
injectDeprecatedContainer(injectedFactory.prototype, container); | ||
} | ||
|
||
injectedFactory.reopenClass(factoryInjections); | ||
|
||
if (factory && typeof factory._onLookup === 'function') { | ||
|
@@ -255,7 +270,14 @@ function injectionsFor(container, fullName) { | |
registry.getTypeInjections(type), | ||
registry.getInjections(fullName)); | ||
injections._debugContainerKey = fullName; | ||
injections.container = container; | ||
|
||
setOwner(injections, container.owner); | ||
|
||
// TODO - Inject a `FakeContainer` instead here. The `FakeContainer` will | ||
// proxy all properties of the container with deprecations. | ||
if (!isEnabled('ember-container-inject-owner')) { | ||
injections.container = container; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. should this occur in There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It has been in |
||
} | ||
|
||
return injections; | ||
} | ||
|
@@ -299,18 +321,40 @@ function instantiate(container, fullName) { | |
|
||
validationCache[fullName] = true; | ||
|
||
let obj; | ||
|
||
if (typeof factory.extend === 'function') { | ||
// assume the factory was extendable and is already injected | ||
return factory.create(); | ||
obj = factory.create(); | ||
} else { | ||
// assume the factory was extendable | ||
// to create time injections | ||
// TODO: support new'ing for instantiation and merge injections for pure JS Functions | ||
return factory.create(injectionsFor(container, fullName)); | ||
obj = factory.create(injectionsFor(container, fullName)); | ||
|
||
if (isEnabled('ember-container-inject-owner')) { | ||
injectDeprecatedContainer(obj, container); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. doesn't this already happen in There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. No, we provide the actual (non deprecated) container in The solution to this is to create a complete There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ah ok, the fakeContainer approach makes sense. |
||
} | ||
} | ||
|
||
return obj; | ||
} | ||
} | ||
|
||
// TODO - remove when Ember reaches v3.0.0 | ||
function injectDeprecatedContainer(object, container) { | ||
Object.defineProperty(object, 'container', { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. we could likely install the container in injections via a symbol, then leave this defProp on CoreObject, that way all ember objects injections don't need to do the redefine. (only those that are not decedents of CoreObject would? |
||
configurable: true, | ||
enumerable: false, | ||
get() { | ||
Ember.deprecate('Using the injected `container` is deprecated. Please use the `getOwner` helper instead to access the owner of this object.', | ||
false, | ||
{ id: 'ember-application.injected-container', until: '3.0.0' }); | ||
return container; | ||
} | ||
}); | ||
} | ||
|
||
function eachDestroyable(container, callback) { | ||
var cache = container.cache; | ||
var keys = Object.keys(cache); | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
import { symbol } from 'ember-metal/utils'; | ||
|
||
export const OWNER = symbol('OWNER'); | ||
|
||
export function getOwner(object) { | ||
return object[OWNER]; | ||
} | ||
|
||
export function setOwner(object, owner) { | ||
object[OWNER] = owner; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
import { getOwner, setOwner, OWNER } from 'container/owner'; | ||
|
||
QUnit.module('Owner', {}); | ||
|
||
QUnit.test('An owner can be set with `setOwner` and retrieved with `getOwner`', function() { | ||
let owner = {}; | ||
let obj = {}; | ||
|
||
strictEqual(getOwner(obj), undefined, 'owner has not been set'); | ||
|
||
setOwner(obj, owner); | ||
|
||
strictEqual(getOwner(obj), owner, 'owner has been set'); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. should this test also assert the "symbol" nature of this |
||
|
||
strictEqual(obj[OWNER], owner, 'owner has been set to the OWNER symbol'); | ||
}); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
import EmberObject from 'ember-runtime/system/object'; | ||
import Registry from 'container/registry'; | ||
import RegistryProxy from 'ember-runtime/mixins/registry_proxy'; | ||
import ContainerProxy from 'ember-runtime/mixins/container_proxy'; | ||
|
||
export default function buildOwner(props) { | ||
let Owner = EmberObject.extend(RegistryProxy, ContainerProxy, { | ||
init() { | ||
this._super(...arguments); | ||
const registry = this.__registry__ = new Registry(); | ||
this.__container__ = registry.container({ owner: this }); | ||
} | ||
}); | ||
return Owner.create(props); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
is this TODO intended for this PR or a future one?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Future PR