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

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.

Related

grails 2.5 how to validate domain object password with service inside validator

We have a simple operator object, which uses spring security to encode the password thusly:
class Operator
transient springSecurityService
def siteService
String username
Site site
String password
def beforeInsert() {
encodePassword()
}
def beforeUpdate() {
if (isDirty('password')) {
encodePassword()
}
}
protected void encodePassword() {
password = springSecurityService?.passwordEncoder ? springSecurityService.encodePassword(password) : password
}
Now we want to validate that the password matches a regexp which is defined at runtime. Operators can be created via the UI (i.e. standard CRUD forms). We have a different regexp for each site. The fact that the password gets overwritten with an ecoded one, and we should not test that, makes it more challenging.
Attempt 1: do the validation in the encodePassword():
def beforeInsert() {
protected void encodePassword() {
String regexp = siteService.getInheritedValue(site, "operatorPasswordRegexp")
if (!password.matches(regexp) {
thrown new RuntimeException "invalid password format"
}
password = springSecurityService?.passwordEncoder ? springSecurityService.encodePassword(password) : password
}
}
This partially works, in that it stops passwords which don't match a regexp found at runtime being created. The problem is it throws an exception, which generates a 500 error page, when we want the operator edit form to highlight the password field with a nice friendly validation message.
Attempt two, using a custom validator
static constraints = {
password password: true, blank:false, validator: { val, obj ->
if (obj.isDirty(val)) {
return true
}
String regexp = obj.siteService.getInheritedValue(obj.operates, "operatorPasswordRegexp")
if (regexp != null && regexp != "") {
return val.matches(regexp)
}
return true
}
This appears to work, but the save always fails silently. It took me some time to realise why - when you do this:
operator.password="valid1"
opertor.save(failonError:true)
No errors are thrown. Even if you remove failonError, and check the return value,its always null (no errors). BUT IT DOES NOT SAVE THE OPERATOR.
The problem is that the beforeInsert is updating the password to an encoded version which does not pass the validator of course (and isnt supposed to), the validator says no at this point, and the save silently fails. I.e. the validiator is being called twice for a single save.
The question is, how to I get the beforeInsert() code to NOT call the validator, or the validator to ignore being called from beforeInsert?
You can achieve your task using both approaches.
1: Do the validation in the encodePassword(): Instead of throwing the exception, add an error to instance. I think your encodePassword() function is in your same domain, so get errors object associated to it using this.errors. ex:
this.errors.rejectValue("password", "user.password.pattern.error")
There are different rejectValue methods, this one accepts the field name and the message code defined in your message.properties file.
2: Custom Validator:
isDirty() is not a static method, call it using the obj provided in the custom validator. isDirty() accepts the property name to be checked for dirtiness not its value.
obj.isDirty(PropertyName)
constraints is a static block, it would not be able to directly access your service. You need to inject your service using static context.
static SiteService siteService;
I would recommend to do it using custom validator.

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

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'

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.

Doctrine 2 self-referencing entity won't return the parent id

I've set up a self-referencing entity per the manual here:
http://www.google.com/url?sa=D&q=http://www.doctrine-project.org/docs/orm/2.0/en/reference/association-mapping.html%23one-to-many-self-referencing
My class is Page (instead of Category, like in the docs). In my entity
class I have a toArray() method that I've implemented that will give
me back the values of my member variables. For those fields that are
associations, I've made sure to grab the associated class object then
grab the id. I'm doing this to populate a form. Here is the code from
my toArray() method in my Page entity as well as my PageService
function to grab a Page object and my Page Controller code that calls
toArray() to populate my form.
http://pastie.org/1686419
As I say in the code comments, when the toArray() method is called in
the Page Controller, all values get populated except for parent id.
page_type is also a ManyToOne association and it gets populated no
problem. Explicitly grabbing the parent id from the Page object
outside of the toArray() method (in the Page Controller) does return
the parent id value. (See code.)
As a side note, I'm using __get() and __set() in my Page entity instead of full blown getters/setters.
I think it is because you are getting caught out by proxies. When you have an association in Doctrine 2, the related objects are not returned directly as objects, but as subclasses which do not fill their properties until a method is called (because of lazy loading to save database queries).
Since you are calling the property directly (with $this->parent->id) without invoking any method the object properties are all empty.
This page http://www.doctrine-project.org/docs/orm/2.0/en/tutorials/getting-started-xml-edition.html#a-first-prototype has a warning about this type of thing in the warning box. Although yours isn't a public property, you are accessing as though it were because that object is of the same class and the same problem is occuring.
Not sure of exactly what is causing your described behavior, but you're probably better anyway to have your toArray() method call getters/setters rather than having toArray() operate directly on the class properties. This will give you consistency so that if you implement custom getters for certain properties, you'll always get back the same result from toArray() and the getter.
A rough example:
<?php
/** #Entity */
class MyEntity {
// ....
/** #Column */
protected $foo;
public function setFoo($val)
{
$this->foo = $val;
}
public function getFoo()
{
return 'hello ' . $this->foo;
}
public function toArray()
{
$fields = array('foo');
$values = array();
foreach($fields as $field) {
$method = 'get' . ucfirst($field);
if (is_callable(array($this, $method)) {
$fields[$field] = $this->$method();
} else {
$fields[$field] = $this->$field;
}
}
return $fields;
}
}
Now you get the same result:
<?php
$e = new MyEntity;
$e->setFoo('world');
$e->getFoo(); // returns 'hello world'
$e->toArray(); // returns array('foo' => 'hello world')

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.