Inspect Ember.js: Get the type of an object (Class)? - ember.js

I use console.log() a lot, especially in combination with Ember.inspect(). But there's one thing I miss:
How can I find out the type of an object (Class)?
For example: Getting something like <Sandbox.ApplicationController:ember288> when inspecting Ember.get("controller")?

If you just want the model name (for example app/models/comment.js has the model name comment), you can use thing.constructor.modelName.
For example:
var aComment = this.get('store').createRecord('comment');
aComment.get('constructor.modelName') // => 'comment'

I understand you are looking for a string for debugging purposes, but I originally came to this question wanting to know specifically how to get the type of the object, not a string describing the object.
Using the built in Javascript property constructor will yield the class used to construct the instance. For example you could do:
person = App.Person.create();
person.constructor // returns App.Person
person.constructor.toString() // return "App.Person"

If you get Class, you can usually call toString() (or as a shortcut concat an empty string + '') to get something like <Sandbox.ApplicationController:ember288>

Another useful feature (in chrome) is the dir command.
dir(App.User)
This will give you the full object information, rather than just the name.

Be aware that some of these answers suggested here only work in development. Once your code is in production most of those methods / class names will get minified.
import Model from '#ember-data/model';
export default class Animal extends Model {
// ...
}
So in development:
const model = this.store.createRecord('animal');
model.constructor.name // returns Animal
in production:
const model = this.store.createRecord('animal');
model.constructor.name // returns 'i' (or any other single letter).
To avoid this, use constructor.toString()
const model = this.store.createRecord('animal');
model.constructor.toString() // returns 'model:animal'

Related

Zend framework 3 form issue with binding entities that use return type hinting

As I'm upgrading my application to PHP 7.3, I decided to add return type hinting to my entities methods.
An example would be something like this:
class User {
private $username;
public method getUsername(): string { return $this->username}
}
I use this entity in a form (to create users) where I bind it like so:
$user = new User();
$form->bind($user);
$form->setData($data);
However I get this error which is caused by the hydrator (I'm using the DoctrineObject hydrator)
Return value of Admin\Entity\Auth\User::getUsername() must be of the type string, null returned
#0 ...\vendor\doctrine\doctrine-module\src\DoctrineModule\Stdlib\Hydrator\DoctrineObject.php(220): Admin\Entity\Auth\User->getUsername()
#1 ...\vendor\doctrine\doctrine-module\src\DoctrineModule\Stdlib\Hydrator\DoctrineObject.php(116): DoctrineModule\Stdlib\Hydrator\DoctrineObject->extractByValue(Object(Admin\Entity\Auth\User))
#2 ...\vendor\zendframework\zend-form\src\Fieldset.php(650): DoctrineModule\Stdlib\Hydrator\DoctrineObject->extract(Object(Admin\Entity\Auth\User))
...
From the snippet above it's obvious that it's calling the getUsername method on an "empty" object, which makes it return null and throw the exception.
This is not logically correct as the entity is supposed to have a username so marking it as nullable (?string) is not correct.
Is there any better solution to this? Because making every single method return type nullable seems like a hack that defeats the purpose.

How to get an Ecore feature disply name without an object instance?

I'd like to create a GUI table to display a given list of features of an EObject sub-class. To do this I have to get the display names of the features for the column header.
How do I get the feature display names in the best way?
One solution that seems a bit like a hack:
If I have an instance of the class then I can use the adaptor factory to get a IItemPropertySource that can do this:
SomeEntity e = ...
String displayName = adaptorFactory.adapt(e, IItemPropertySource.class)
.getPropertyDescriptor(null, feature).getDisplayName(null));
But when the table is empty there is no SomeEntity object handy to use to get the IItemPropertySource.
I can create a dummy object using the EFactory in this way:
EClass containingClass = feature.getEContainingClass();
SomeEntity dummy = containingClass.getEPackage().getEFactoryInstance()
.create(containingClass));
... and then use that object the get the IItemPropertySource. But this seem a bit like a hack. Is there no better solution?
If you know the class at compile time, you can create the ItemProviderAdapter yourself:
MyClassItemProvider provider = new MyClassItemProvider(adaptorFactory);
String name = provider.getPropertyDescriptor(null, property).getDisplayName(null);
If you do not know the class at compile time, but only have an EClass instance at runtime, things are more complicated, because the necessary methods are protected. You have to "make" them public first.
I would add respective methods to the generated MyPackageSwitch and MyPackageAdapterFactory classes (in myPackage.util).
In MyPackageAdapterFactory:
/**
* #generated NOT
*/
public MyPackageSwitch<Adapter> getModelSwitch() {
return modelSwitch;
}
In MyPackageSwitch:
/**
* generated NOT
*/
public T doPublicSwitch(EClass theEClass, EObject theEObject) {
return doSwitch(theEClass, theEObject);
}
Now you can create an ItemProviderAdapter for an EClass theEClass like this:
provider = (ItemProviderAdapter) adapterFactory.getModelSwitch()
.doPublicSwitch(theEClass, null);
EMF was obviously not made for this. Keep in mind that this all is only working if you do not have any custom provider implementations that uses the EObject values.

How to get store name of Ember Data model

How can I determine the "store name" (not sure what the proper terminology is) for a given ED Model? Say I have App.Payment, is there a store method that let's me look up its corresponding name, i.e. payment (for example to use in find queries)?
For Ember Data 1.0 (and later)
modelName is a dasherized string. It stored as a class property, so if you have an instance of a model:
var model = SuperUser.create();
console.log(model.constructor.modelName); // 'super-user'
For Ember Data Pre 1.0
typeKey is the string name of the model. It gets stored as a class property of the model, so if you have an instance of a model:
var model = App.Name.create({});
console.log(model.constructor.typeKey); // 'name'
You might be looking for Ember's string dasherize method:
var fullClassName = "App.SomeKindOfPayment";
var className = fullClassName.replace(/.*\./, ""); // => "SomeKindOfPayment"
var dasherizedName = Ember.String.dasherize(className); // "some-kind-of-payment"
There might be a built-in way to do this in Ember, but I haven't found it after spending some time looking.
EDIT: Ember Data might also let you get away with passing "App.SomeKindOfPayment" when a model name is needed - it usually checks the format of the model name and updates it to the required format by itself.
store.find, store.createRecord, and other persistence methods, use the store.modelFor('myModel'). After some setup it call container.lookupFactory('model:' + key); where key is the 'myModel'. So any valid factory lookup syntax is applicable. For example:
Given a model called OrderItems you can use: order.items, order_items, order-items, orderItems.
It turns out there was no need to do this after all, and here's why:
I was trying to the the string representation of the model ("payment" for App.Payment) in order to call store.findAll("payment"). However, looking at the ED source for store, the findQuery function calls modelFor to look up the factory (App.Payment) from the string (payment), unless a factory is already provided. And the factory is easily accessible from the controller by calling this.get('model').type. There's no need to convert it to a string (and back).
Here's the relevant code from the Ember Data source.
modelFor: function(key) {
var factory;
if (typeof key === 'string') {
factory = this.container.lookupFactory('model:' + key);
Ember.assert("No model was found for '" + key + "'", factory);
factory.typeKey = key;
} else {
// A factory already supplied.
factory = key;
}
factory.store = this;
return factory;
},

Pyamf register_class not mapping strongly typed objects as expected

I'm using Pyamf as my backend for my Flex app and I'm seeing some weird problems with the mapping of the stongly typed classes.
Here is the model that I'm returning
class MilestonActBase(RewardActBase):
def __unicode__(self):
return self.milestone.title
class Meta:
abstract = True
class SouvenirAct(MilestonActBase):
souvenir = models.ForeignKey(Souvenir)
group = models.ForeignKey(Group, blank=True, null=True)
def __unicode__(self):
return self.souvenir.title
Here is my method that returns the objects in my views.py:
try:
pyamf.register_class(Souvenir, 'com.rain.dennys.services.vo.Souvenir')
pyamf.register_class(SouvenirAct, 'com.rain.dennys.services.vo.SouvenirAct')
except ValueError:
print "Classes already registered"
#login_required
def get_souvenir_acts(http_request):
user = http_request.user
souvenirActs = SouvenirAct.objects.filter(user=user)
return souvenirActs
Here is my AS3 class:
package com.rain.dennys.model
{
[RemoteClass (alias="com.rain.dennys.services.vo.SouvenirAct")]
[Bindable]
public class SouvenirAct extends RewardActBase
{
public var souvenir:Souvenir;
public function SouvenirAct()
{
}
}
}
When I call the service, I get back and array of anonymous objects, even though I've done the register_class in python and RemoteClass in Flex. So that doesn't make sense to me. I must be doing something wrong?
In playing around with it, I've tried a few different things. One thing that kinda worked was to iterate on the array in Flex and cast the items as SouvenirAct objects like so:
private function onResult(r:Array):void
{
for each(var o:Object in r)
{
var c:SouvenirAct = o as SouvenirAct;
}
}
When I do that in Flex, I get my SouvenirAct objects are typed as they should be, BUT then the child souvenir objects are all null. So when I force the casting of the SouvenirAct objects in the return result, I get null for the child properties that are strongly typed.
Has anyone see this before? Is there a different way I should be mapping classes?
So I'm now pretty certain the problem was with the netConnection class. I switched it out so I could use RemoteObject, and now everything works exactly as expected.
This is how I was connecting:
netConnection.connect("http://127.0.0.1:8000/gateway/");
netConnection.addEventListener(NetStatusEvent.NET_STATUS, onError);
var responder:Responder = new Responder(onResult, handleFault);
Then I switched to what is described here: http://www.adobe.com/devnet/flex/articles/flex_django.html If anyone else runs into this, and you are using netConnection, my advice is to go with RemoteObject
Okay, so this is kind of a guess but this has stung me a few times. Have you ever instantiated an instance of Souvenir anywhere in your flex application? If not... AS did not bother to compile it and you'll get anonymous objects back.
When you do your onResult looping block of code, it works because you're instantiating an object of SouvenirAct, but never instantiating a Souvenir (child), so it's still null because ActionScript never compiled it...Try this before your service call
//TODO: remove me later
var imjustheretocompile:Souvenir = new Souvenir();
var alsoCompileMetoo:SouvenirAct = new SouvenirAct();
Now since you've created an instance of SouvenirAct, it should actually be compiled into your app. This is usually never a problem since we presume you will be using that class at some point, then you can go back and remove the imjustheretocompile and alsoCompileMetoo variables.

How do I test rendered views when using T4MVC with TestHelper?

How do I test which view was rendered from a controller action if what I get is a T4MVC_ActionResult? Under normal circumstances I should be able to directly use TestHelper's methods, like in the examples:
pooController.Details().AssertViewRendered().ForView("Details")
...but, since through T4MVC I get a T4MVC_ActionResult instead of a ViewResult, the part AssertViewRendered<>().ForView("Details") fails. What alternative do I have if I want to test which view was invoked?
UPDATE:
Here's the test code:
[TestMethod]
public void Theme_Controller_Details_Action_Returns_Details_View()
{
var builder = new TestControllerBuilder();
var mockThemeRepository = new Mock<IThemeRepository>();
var themeController = builder.CreateController<Evalgrid.Website.Controllers.ThemeController>(mockThemeRepository.Object);
builder.InitializeController(themeController);
var result = themeController.Details();
result.AssertViewRendered().ForView("Details");
}
I used the debugger setting a breakpoint after the result line, and its variable type is T4MVC_ActionResult, while themeController is Evalgrid.Website.controllers.ThemeController. Note that I have used the fully qualified name of the controller.
I get this:
Expected result to be of type
ViewResult. It is actually of type
T4MVC_ActionResult.
I don't know what's going on.
Actually, T4MVC should not make a difference here. If you directly instantiate your controller and call an action method, you'll get the same thing back whether you use T4MVC or not. i.e. you won't get a T4MVC_ActionResult.
It's only when you write MVC.Foo.Details() that you'll get a T4MVC_ActionResult. That's because MVC.Foo returns an instance of a derived class which does special thing, and not directly your controller class.
Does that make sense?
Update: I'm confused, as looking at the sources for TestControllerBuilder.CreateController, it has:
public T CreateController<T>(params object[] constructorArgs) where T : Controller
{
var controller = (Controller)Activator.CreateInstance(typeof(T), constructorArgs);
InitializeController(controller);
return controller as T;
}
So it's directly instantiating the type that you pass in, which should just call your normal action.
One question about your code: does your Details action method take any parameters? If so, that would explain the problem, as you're calling it with no params, which would be a T4MVC method added in the partial class.