This question already has an answer here:
Why do I receive "This value should be of type string" when using a DateTime constraint on Symfony 5?
(1 answer)
Closed 2 years ago.
I migrated a project from Symfony 3.4 to Symfony 4.4 (back side with API platform)
In an entity I have a date field, which is automatically generated on today's date, So when I make a POST or a PUT, she is not in my JSON
/**
* #Groups({"get_logement", "post_logement", "put_logement"})
* #ORM\Column(type="datetime", nullable=false)
* #Assert\Date(message="the date is not correct.")
*/
private $dateEtat;
public function getDateEtat(): ?\DateTimeInterface
{
return $this->dateEtat;
}
public function setDateEtat(?\DateTimeInterface $dateEtat): self
{
$this->dateEtat = $dateEtat;
return $this;
}
and a construct :
public function __construct()
{
$this->dateEtat = new \Datetime();
}
since version 4.4 when I do a POST or a PUT, I get this error
"type": "https://tools.ietf.org/html/rfc2616#section-10",
"title": "An error occurred",
"detail": "dateEtat: Cette valeur doit être de type string.",
"violations": [
{
"propertyPath": "dateEtat",
"message": "This value must be of type string."
}
]
See : https://github.com/symfony/symfony/issues/29646
Validating a \DateTimeInterface with "Symfony\Component\Validator\Constraints\DateTime"
is deprecated since version 4.2.
Use "Symfony\Component\Validator\Constraints\Type" instead
or remove the constraint if the underlying model is already type hinted to \DateTimeInterface.
Related
Consider the following output is produced:
Case 1: while retrieving the nested object from neo4j using spring data neo4j interface (projection)
{
"name": "Dhoni",
"currentLocation": {
"city": {
"name": "qwerqwer",
"regionalState": {
"state": {
"name": "zxvcxzcvc"
}
}
}
}
}
Projection Interface:
public interface PersonProjection {//Root
String getName();
CurrentLocationProjection getCurrentLocation();
public interface CurrentLocationProjection { // has relationship Props
CityProjection getCity(); // target object in entity mapping
interface CityProjection {
String getName();
RegionalStateProjection getRegionalState();
interface RegionalStateProjection { // has relationship Props
StateProjection getState(); // target object in entity mapping
interface StateProjection {
String getName();
}
}
}
}
}
Case 2: When i tried to get the nested values mapped to 1st level using SpEL, works fine as u can see below
public interface PersonProjection {//Root
String getName();
CurrentLocationProjection getCurrentLocation();
public interface CurrentLocationProjection {
#Value("#{target.city.name}")
String getCityName();
#Value("#{target.city.regionalState.state.name}")
String getStateName();
}
}
gives output as:
{
"name": "Deva",
"currentLocation": {
"cityName": "qwerqwer",
"stateName": "zxvcxzcvc"
}
}
Case 3:
Issue:
However, when i try to get nested values mapped to (root level / root node) itself using SpEL via #Value as below:
public interface PersonProjection {
String getName();
#Value("#{target.currentLocation.city.name}")
String getCityName();
#Value("#{target.currentLocation.city.regionalState.name}")
String getStateName();
}
expected output:
{
"name": "Dhoni",
"cityName": "qwerqwer",
"stateName": "zxvcxzcvc"
}
But, it throws the following error stating currentLocation is null as below: (but it has value)
WARN 13600 --- [nio-8080-exec-6] .w.s.m.s.DefaultHandlerExceptionResolver : Resolved [org.springframework.http.converter.HttpMessageNotWritableException: Could not write JSON: EL1007E: Property or field 'city' cannot be found on null; nested exception is com.fasterxml.jackson.databind.JsonMappingException: EL1007E: Property or field 'city' cannot be found on null (through reference chain: com.sun.proxy.$Proxy162["currentLocation"])]
I'm bit confused how it works in 1st-level and not in the root level?
could someone please point my mistake / guide me to achieve the expected output. Thanks.
Note: SDN (Spring Data Neo4j) version 6.1.2 for ref.
There was a bug in Spring Data Neo4j regarding Spring Expression Language using related entities that are not part of the projection.
https://github.com/spring-projects/spring-data-neo4j/issues/2325
tl;dr;
it is solved in Spring Data Neo4j 6.1.3
I´ve just replaced the Composer default sample ("sampleAsset", "sampleTransaction", etc) by another one I created, for my better understanding. Everything works except for the transaction, which return me the error message:
"**Error: Could not find any functions to execute for transaction org.acme.sample.CompraDoVinho#**2b2d0624-bc..."
Find below the source codes:
Blockquote
Model file:
namespace org.acme.sample
asset Vinho identified by IDvinho {
o String IDvinho
--> Participante owner
o String uva
o String nomeVinho
o Integer preco
}
participant Participante identified by IDparticipante {
o String IDparticipante
o String tipo
o String nomeEmpresa
}
transaction CompraDoVinho identified by IDcompra {
o String IDcompra
--> Vinho asset
o Integer precoVenda
}
Logic:
function onSampleTransaction(CompraDoVinho) {
CompraDoVinho.asset.preco = CompraDoVinho.precoVenda;
return getAssetRegistry('org.acme.sample.Vinho')
.then(function (assetRegistry) {
return assetRegistry.update(CompraDoVinho.asset);
});
}
Permissions:
rule Default {
description: "Allow all participants access to all resources"
participant: "ANY"
operation: ALL
resource: "org.acme.sample"
action: ALLOW
}
Blockquote
Could anybody help me finding where is the bug in my code?
Thanks in advance
The issue is almost certainly because you've renamed the transaction. Composer has 2 mechanisms to route transactions to JS functions:
(Legacy) using an onMyTransactionType naming convention. I.e. the function will be called when an instance of MyTransactionType is submitted.
(Preferred) using the #transaction and #param annotations. See below for an example. The #transaction annotation indicates that the function would like to process transactions and the #param annotation is used to specify the type of the transaction to process.
/**
* Place an order for a vehicle
* #param {org.acme.vehicle.lifecycle.manufacturer.PlaceOrder} placeOrder - the PlaceOrder transaction
* #transaction
*/
function placeOrder(placeOrder) {
console.log('placeOrder');
let factory = getFactory();
let NS = 'org.acme.vehicle.lifecycle.manufacturer';
let order = factory.newResource(NS, 'Order', placeOrder.transactionId);
order.vehicleDetails = placeOrder.vehicleDetails;
order.orderStatus = 'PLACED';
order.manufacturer = placeOrder.manufacturer;
// save the order
return getAssetRegistry(order.getFullyQualifiedType())
.then(function (registry) {
return registry.add(order);
});
}
Absolutely. The annotation is essential for the function to work!
#param must state the class name of the transaction and the param name
#transaction declared underneath, with function to follow in block below
#param {org.acme.mynetwork.Foo} foo - the report to be processed
* #transaction
Please Replace the code in your logic.js file with following code and the error will surely be gone. Mine was the same problem, I just added the required JS doc annotations above the function and the same issue was resolved!
'use strict';
var NS = 'org.acme.sample';
/**
* #param {org.acme.sample} CompraDoVinho
* #transaction
*/
function onSampleTransaction(CompraDoVinho) {
CompraDoVinho.asset.preco = CompraDoVinho.precoVenda;
return getAssetRegistry('org.acme.sample.Vinho')
.then(function (assetRegistry) {
return assetRegistry.update(CompraDoVinho.asset);
});
}
Hope this helps you!
I am currently having issues validating my constraint messages in spock using grails 2.4.2. When testing i keep getting the default error message rather than my custom message. However when i print to a view using grails error tag i get the correct error message. I have even deleted the default from message.propperties.
Here is what my spec looks like:
import com.fishLogger.user.User
import com.fishLogger.DomainErrorHandling
import grails.test.mixin.TestFor
import org.springframework.context.MessageSource
import spock.lang.Specification
/**
* See the API for {#link grails.test.mixin.domain.DomainClassUnitTestMixin} for usage instructions
*/
#TestFor(User)
class UserSpec extends Specification {
MessageSource messageSource
def setup() {
DomainErrorHandling.enable(new User())
}
def cleanup() {
}
void "test Invalid User Name Errors"(){
when:
User user = new User(userName:userName, password:password, email:email)
//user.errors.allErrors.get(0).code
user.validate()
then:
user.errorMessage()==expectedMessage
where:
userName | password | email | expectedMessage
"" |"vailidPassword" | "thisworks#email.com" | "User name must be entered"
//"asd" |"vailidPassword" | "thisworks#email.com" | "User name must be atleast 6 chacters long"
//" " |"vailidPassword" | "thisworks#email.com" | "User name must be entered"
//"aaaaaaaaaaaaaaaaaaaaa" |"vailidPassword" | "thisworks#email.com" | "User name can not be greater than 20 characters"
}
Where enable is a call loading a helping method to the domain to grab the error message
class DomainErrorHandling {
public static void enable(Object obj){
obj.class.metaClass.errorMessage = {
MessageSource messageSource = Holders.applicationContext.getBean("messageSource")
def errorString = delegate?.errors?.allErrors?.collect{error ->
messageSource.getMessage(error,Locale.default)
}?.join(' \n')
return errorString
}
}
}
Any help or guidance would be great. I know that testing the error messages should be more of a UI test but i would really prefer to test them with my unit tests as well.
As for why it still shows the old message when you delete it from message.properties, check out the getDefaultMessage() in MessageSourceResolvable. I'm guessing that your custom message isn't visible to the test, either because its key is misspelled or some Grails test bootstrap problem.
I would try printing out the getCodes() of the error in your errorMessage() method, and see if any of the codes listed is the key to one of your custom ones in message.properties.
Assuming a Book domain class with a non nullable name property you can do the following:
#Mock(Book)
class BookSpec extends Specification {
StaticMessageSource messageSource
def setup () {
messageSource = (StaticMessageSource)grailsApplication.mainContext.getBean('messageSource')
}
def "check name validation error message" () {
given:
messageSource.addMessage ("nullable.name", Locale.default, "Null!")
Book book = new Book (name:null)
when:
book.validate ()
then:
messageSource.getMessage (book.errors.getFieldError ('name'), Locale.default) == "Null!"
}
}
I am using Docrine 1.2 with Zend Framework and trying to save a Doctrine Collection.
I am retrieving my collection from my table class with the following code.
public function getAll()
{
return $this->createQuery('e')
->orderBy('e.order ASC, e.eventType ASC')
->execute();
}
I also have the following class to reorder the above event records.
class Admin_Model_Event_Sort extends Model_Abstract
{
/**
* Events collection
* #var Doctrine_Collection
*/
protected $_collection = null;
public function __construct()
{
$this->_collection = Model_Doctrine_EventTypesTable::getInstance()->getAll();
}
public function save($eventIds)
{
if ($this->_collection instanceof Doctrine_Collection) {
foreach ($this->_collection as $record)
{
$key = array_search($record->eventTypeId, $eventIds);
if ($key !== false) {
$record->order = (string)$key;
}
}
return $this->_saveCollection($this->_collection);
} else {
return false;
}
}
}
The _saveCollection method above is as follows
/**
* Attempts to save a Doctrine Collection
* Sets the error message property on error
* #param Doctrine_Collection $collection
* #return boolean
*/
protected function _saveCollection(Doctrine_Collection $collection)
{
try {
$collection->save();
return true;
} catch (Exception $e) {
$this->_errorMessage = $e->getMessage();
OpenMeetings_Logger_ErrorLogger::write('Unable to save Doctrine Collection');
OpenMeetings_Logger_ErrorLogger::vardump($this->_errorMessage);
return false;
}
}
The event id's in the above save method is simply an enumerated array of event id's, I am using the keys of the array to set the sort order of the events using the order field. If I do a var_dump of the collection to an array ($this->_collection->toArray()) I get the correct data. However when I attempt to save the collection I get the following error.
"SQLSTATE[42000]: Syntax error or access violation: 1064 You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'order = '0' WHERE eventtypeid = '3'' at line 1"
Is there anyway I can get Doctrine to expand on this error, the full SQL statement would be a start, also if anyone knows as to why this error is occuring then that would be very helpful.
Many thanks in advance
Garry
EDIT
I have modified my above code to try to work one record at a time but I still get the same problem.
public function save($eventIds)
{
foreach ($eventIds as $key => $eventId) {
$event = Model_Doctrine_EventTypesTable::getInstance()->getOne($eventId);
$event->order = (string)$key;
$event->save();
}
}
Ok I have found the problem. I was using the MYSQL reserved word order as a field name thus the error, changed it to sortOrder and the problem went away.
Hope this helps someone with a similar issue.
Garry
I have the following code, which retrieves the page slugs from the database which are needed to then create a related sub page:
$builder->add('subtocontentoptions', 'entity', array(
'class' => 'ShoutAdminBundle:Content',
'property' => 'slug',
'query_builder' => function($repository) {
return $repository->createQueryBuilder('p')
->where('p.mainpage = :main')
->setParameter('main', '1')
->orderBy('p.created', 'ASC');
}
));
The code works, as it displays a drop down menu of all the parent pages I have. However, when I go to save the data to the database, I am given the following error:
ErrorException: Catchable Fatal Error: Object of class
Shout\AdminBundle\Entity\Content could not be converted to string in
C:\wamp\www\vendor\doctrine-dbal\lib\Doctrine\DBAL\Statement.php line
131
I have checked the contents of the Content entity file, and here is the variable being declared:
/**
* #var integer $subtocontentoptions
*
* #ORM\Column(name="SubToContentOptions", type="integer", nullable=false)
*/
private $subtocontentoptions;
And lower down the Content entity file:
/**
* Set subtocontentoptions
*
* #param integer $subtocontentoptions
*/
public function setSubtocontentoptions($subtocontentoptions)
{
$this->subtocontentoptions = $subtocontentoptions;
}
/**
* Get subtocontentoptions
*
* #return integer
*/
public function getSubtocontentoptions()
{
return $this->subtocontentoptions;
}
The rest of the code does work, once this drop down has been taken out. I'm not sure why the drop down is causing this error?
Thanks
Was having the same issue with a sf2/doctrine2 project, implementing the __toString method resolved this issue for me :
public function __toString()
{
return strval($this->id);
}