NULL value found, but an object is required in assertMatchesResourceCollectionJsonSchema - symfony

I have created and entity with OneToOne relation to other entity.
For the sake of simplicity I will only show related props of those entities
class Comment
{
#[ORM\OneToOne(inversedBy: 'comment', targetEntity: Answer::class)]
#[ApiProperty(readableLink: true)]
#[ORM\JoinColumn(nullable: true)]
private ?Answer $answer = null;
}
class Answer
{
#[ORM\OneToOne(mappedBy: 'answer', targetEntity: Comment::class)]
private Comment $comment;
}
Comment can exist without Answer but Answer cannot exist without Comment and each Comment can only have exactly one Answer.
Those entities works just fine but when it comes to tests I have and error mentioned in title of this question.
body of test:
use ApiPlatform\Core\Bridge\Symfony\Bundle\Test\ApiTestCase;
class CommentTest extends ApiTestCase
{
public function testGetComments(): void
{
$response = static::createClient()->request('GET', '<url>');
self::assertResponseIsSuccessful();
self::assertMatchesResourceCollectionJsonSchema(Comment::class);
}
}
In this test I am getting an error in assertMatchesResourceCollectionJsonSchema.
hydra:member[0].answer: NULL value found, but an object is required
hydra:member[0].answer: Failed to match at least one schema
Why object is required when in Comment entity there is provided ? and #[ORM\JoinColumn(nullable: true)] which states that this property can be "NULL"
Update
After some investigation I have found that the culprit is #[ApiProperty(readableLink: true)] in Comment entity. API works just fine with this but for some reason tests do not want to cooperate.

Related

Custom class level bean validation constraint

I already know how to add annotation based validation on specific attributes in Entity class like :-
public class Person {
#NotNull
private String firstName;
private String lastName;
//...
}
But is it possible to add annotation on class Person, in order to validate all the attributes inside this class, by creating a Customised Validation Class and handling validation there somewhere like :-
#Retention(value = RetentionPolicy.RUNTIME)
#Target(value = ElementType.METHOD)
public #interface PersonneName {
public String firstName();
}
I am working on a project to get Constraints from Database and creating Customised Validation Class and applying on the Entity class attributes according to the constaints got from DB.
Please suggest.
Yes, of course, it's possible. First, create the definition of your annotation. Pretty much like you did in your example, however, with a different #Target type
#Target({ElementType.TYPE, ElementType.ANNOTATION_TYPE})
#Retention(RetentionPolicy.RUNTIME)
#Constraint(validatedBy = PersonValidator.class)
public #interface ValidPerson {
String message () default "Your custom message";
Class<?>[] groups () default {};
Class<? extends Payload>[] payload () default {};
}
Then implement the validator whose isValid method takes the instance of your Person class:
public class PersonValidator implements ConstraintValidator<ValidPerson, Person> {
#Override
public boolean isValid (Person person, ConstraintValidatorContext context) {
// your validation logic
}
}
Sure it is possible, just check the documentation regarding how to write custom class level constraints - http://docs.jboss.org/hibernate/stable/validator/reference/en-US/html_single/#section-class-level-constraints
The important thing of course is that you make sure that one can actually place the constraint annotation on the type level. For that you need to add ElementType.TYPE to the #Target annotation.

pojo with embedded entity class

We have the following situation: an entity and a pojo in Objectify v5.
As you can see, the entityclass has a reference to the pojo, like this:
#Entity
public class TestCustomer {
#Id
public Long id;
TestIbj ibj;
}
class TestIbj {
TestCustomer customer;
}
This fails with a StackOverflowError when we try to save it like this:
TestCustomer testCustomer = new TestCustomer();
OfyService.ofy().save().entity(testCustomer).now();
Error:
java.lang.StackOverflowError
at java.lang.Class.getMethod0(Class.java:2772)
at java.lang.Class.isCheckMemberAccessOverridden(Class.java:2214)
at java.lang.Class.checkMemberAccess(Class.java:2233)
at java.lang.Class.getDeclaredMethods(Class.java:1854)
at...
Our question is: Why is this not allowed/failing? If we change the pojo into an Entity, it works fine, but we don't understand why that is..
Thank you very much!
StackoverflowError almost always means that there is an unbounded recursion. It's the case in your code as well:
#Entity
public class TestCustomer {
#Id
public Long id;
TestIbj ibj; // TestCustomer contains TestIbj
}
class TestIbj {
TestCustomer customer; // TestIbj contains TestCustomer (which further contains TestIbj.. and so on)
}
Due to this circular dependency (shown in code above), objectify will never be able to construct object graph.

How you retrieve the Key<T> when you have an Entity?

I have a class that I loaded using Objectify v5, how do I get the associated Key<T> from Objectify?
#Entity
#Cache
public abstract class BaseEntity<T,P>
{
#Parent
private Key<P> parent;
#Id
private String uuid;
}
I know that ofy().save() returns the Key<T> but I want to get the Key<T> from an Entity that was loaded by a filter or id.
I have searched all over the Objectify v5 documentation and can't find methods that take an Entity and return a Key<T> of that Entity.
Solution
Key.create(T pojo);
But in the case above it doesn't work from inside my BaseEntity<T,P> class.
#Nonnull
public Key<T> getKey() { return Key.create(this); }
Complains that it wants to cast the result to Key<T>.
After some experimenting I just added a method to my BaseEntity
#Nonnull
public Key<T> getKey()
{
return Key.create(this.parent, this.entityType, this.uuid.toString());
}
This returns the same Key<T> that is auto-generated.
Java's typing system is not sophisticated enough to express "i want this to be whatever type 'this' happens to be at the leaf level" (since you are in an abstract class). Scala could do this, but not Java. At least not to my knowledge.
Unless I'm misunderstanding what you are trying to do...?

Symfony error with form entity class

I'm trying to add some validation rules for my form by using callbacks for a few choice fields.
This callback I saw in the documentation should be in the entity class for that form. But in my case I'm having all the time this problem:
"ContextErrorException: Notice: Array to string conversion in /Applications/MAMP/htdocs/bbc/vendor/symfony/symfony/src/Symfony/Component/Form/Extension/Core/ChoiceList/ChoiceList.php line 462"
My code in my entity looks like this:
namespace Cgboard\AppBundle\Forms;
use Cgboard\AppBundle\Classes\Iplayer;
class SearchEntity
{
public $category;
public $coming_soon_within;
public $local_radio;
public $masterbrand;
public $max_tleos;
public $media_set;
public $page;
public $perPage;
public $q;
public $search_availibity;
public $service_type;
public $signed;
public static function getCategories() // all this getters are firing the error, why?
{
return ['undef',
'arts',
'cbcc',
'comedy'];
}
public static function getLocalRadio()
{
......
I want to use these callbacks from my validation.yml file, that looks like this one:
Cgboard\AppBundle\Forms\SearchEntity:
properties:
category:
- Choice: { callback: getCategories }
coming_soon_within:
- Range:
min: 1
max: 168
local_radio:
- Choice: { callback: getLocalRadio }
masterbrand:
- Choice: { callback: getMasterbrand }
....
Even if I delete the whole content from validation.yml I still have the error. So I think the problem is just with the entity form class. Any idea about how to work around this problem?
Because I think can be handy for someone else. The problem was that I was using getters (getLocalRadio for instance) that were creating conflicts for the internal getters used by SYmfony. I just changed the name of these getter and everything worked fine

PHPUnit: what does 'Attribute' refer to?

Sorry if this is a rudimentary question, but what does the term 'Attribute' refer to in the context of PHPUnit testing? I know what properties and methods are, I know what public/private/protected do. I know the different between static and instance variables. But I see all these 'Attribute' oriented asserts in the PHPUnit command sets but none of the documentation I have seems to take the step back to describe what 'attribute' is actually referring to. properties? methods? all of the above???
SW
Properties.
The assertAttribute metods are used to test public and private properties of a class or object.
class Foo {
private $bar = 'baz';
}
class fooTest extends PHPUnit_Framework_TestCase {
// ...
public function testFooAttibute(){
$this->assertAttributeEquals(
'baz', /* expected value */
'bar', /* attribute name */
new Foo /* object */
);
}
}
class something
{
public $i_m = 'attribute';
public function i_m_method()
{
}
}
More to read: http://www.php.net/manual/en/language.oop5.properties.php

Resources