Symfony entity - Oracle default SYSDATE not working - oracle

Symfony 5 + Oracle.
Entity:
/**
* #var \DateTime
*
* #ORM\Column(name="CREATE_DT", type="date", nullable=false, options={"default"="SYSDATE"})
*/
private $createDt = 'SYSDATE';
Controller:
//save entity object to database (createDt property NOT passed, default must be applied)
$em->persist($obj);
$em->flush();
Error:
Could not convert PHP value 'SYSDATE' of type 'string' to type 'date'. Expected one of the following types: null, DateTime (500 Internal Server Error)
How can I make Symfony apply default SYSDATE at flush?

You can init your date with default value directly in the constructor.
class YourEntity {
/**
* #var \DateTime
*
* #ORM\Column(name="CREATE_DT", type="date", nullable=false)
*/
private $createDt;
public function __construct() {
$this->createDt = new \Datetime();
}
}

Related

Access to getDateFormat() from controller - Laravel

Is it possible to access the getDateFormat() method from a controller or command?
I can use it my models like this:
public function getCreatedAtAttribute($value)
{
$format = $this->getDateFormat();
return Carbon::createFromFormat($format, $value, 'UTC')->setTimezone(\Helper::getTimezone());
}
but when using it in my controller or command, like this $format = getDateFormat();, I get the following error:
local.ERROR: exception
'Symfony\Component\Debug\Exception\FatalErrorException' with message
'Call to undefined function App\Console\Commands\getDateFormat()'
Of course you cannot - cause it's a protected method of Model class.
/**
* Get the format for database stored dates.
*
* #return string
*/
protected function getDateFormat()
{
return $this->dateFormat ?: $this->getConnection()->getQueryGrammar()->getDateFormat();
}
And by default it's simply
/**
* Get the format for database stored dates.
*
* #return string
*/
public function getDateFormat()
{
return 'Y-m-d H:i:s';
}
Carbon instance uses this format as default so if you need to get Carbon date - just simply use Carbon::parse($value) - it will sure recognize this type of format. And by default doing (string)Carbon::parse($value) you will get date in this default format cause:
/**
* Format to use for __toString method when type juggling occurs.
*
* #var string
*/
protected static $toStringFormat = self::DEFAULT_TO_STRING_FORMAT;
/**
* Format the instance as a string using the set format
*
* #return string
*/
public function __toString()
{
return $this->format(static::$toStringFormat);
}
Also check Carbon documentation - there are a lot of modifiers like ->toDateString(), ->toDateTimeString()
getDateFormat() is not a native function in php if i remeber its use in drupal
so..
if in your $value you have a timestamp you can use getDate() this will return an array with minute seconde ...
or if your value isn't timestamp you can use dateTime() with format like
public function getCreatedAtAttribute($value)
{
$date = new DateTime($value);
$date->format('Y-m-d H:i:s');
return $date;
}
I hope this help you
good day

Doctrine 2: Oracle Insert Trigger

i currently started to work with the symfony2 framework and doctrine2.
I have the following problem here with using doctrine when I want to insert an object.
Following given situation:
The table uses a sequence, that generates the ID via BEFORE INSERT
Trigger
The sequence is uses by other tables as well, so there is no name
convention like: $table->getName() . '_SEQ'; (see
Doctrine/DBAL/Platforms/OraclePlatform.php getIdentitySequenceName())
The sequence that should be uses id called: general_data_seq
The design of the tables and triggers is given and cannot be changed.
I have made the following entity:
/**
* #ORM\Entity
* #ORM\Table(name="test")
*
*/
class Test
{
/**
* #ORM\Column(type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="IDENTITY")
*/
private $id;
/**
* #ORM\Column(type="string")
*/
private $name;
/**
* #param int $id
*/
public function setId($id)
{
$this->id = $id;
}
/**
* #return string
*/
public function getName() : string
{
return $this->name;
}
/**
* #return string
*/
public function setName(string $name)
{
$this->name = $name;
}
}
If i want to save this using doctrine like this
$em = $this->getDoctrine()->getManager();
$test = new Test();
$test->setName('Max');
$em->persist($test);
$em->flush();
I'm getting the message:
ORA-02289: sequence does not exist.
What is true, since the sequence that should be use really does not exist.
My question now is: How to use docrine here so that the persisted entity has the inserted id generated by the trigger?
I found a related problem here:
Doctrine 2: cascade persist Oracle "IDENTITY" is returning 0 as last inserted ID
and here: https://github.com/doctrine/dbal/issues/1772
but nighter of them helped me to find a solution, since they are still bases on using the table-named-sequence.

Symfony2 conditional form validation

I have some difficulties about applying validation for only one associated entity.
So I have two entities, News and NewsTranslation. A news could be translated in multiple languages. But I would like to apply validation only if locale is en.
// AppBundle/Entity/News.php
class News
{
use ORMBehaviors\Translatable\Translatable;
use ORMBehaviors\Timestampable\Timestampable;
/**
* #var int
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var int
*
* #ORM\Column(name="status", type="smallint")
* #Assert\NotBlank
*/
private $status;
...
}
// AppBundle/Entity/NewsTranslation.php
class NewsTranslation
{
use ORMBehaviors\Translatable\Translation;
/**
* #var string
*
* #ORM\Column(name="title", type="string", length=255, nullable=true)
* #Assert\NotBlank
* #Assert\Length(max = 255)
*/
private $title;
/**
* #var string
*
* #ORM\Column(name="text", type="string", nullable=true)
* #Assert\NotBlank
*/
private $text;
}
# AppBundle/Resources/config/validation.yml
AppBundle\Entity\News:
properties:
translations:
- Valid: ~
I tried to use a Closure for the validation_groups form option. But it looks like Symfony do validation on News entity and Valid constraint apply the same groups on NewsTranslation.
I know I could use Callback constraint but that's mean to redo NotBlank, Length and other exiting constraints by myself. And I would like to avoid it if possible.
EDIT:
I'm using Symfony 2.8.*
I try using an en validation group. But looks like the validation is launch on News entity with validation_groups. And with Valid constraint the en validation group is given to validate NewsTranlation. So even it's the en or fr translation the group change nothing in this case.
I also try using the validation medatada through an #Assert\Callback or by using loadValidatorMetadata method into NewsTranslation entity. And the problem stay similar. I can't apply an constraint for a specific entity of collection.
I finally found a way by creating a custom validator.
Like this I could use core constraints easily.
In the translation entity, I could use my validator like this:
/**
* #var string
*
* #ORM\Column(name="title", type="string", length=255, nullable=true)
* #Assert\Length(max = 255)
* #AppAssert\ValidTranslation(locales = {"fr"}, constraints = {
* #Assert\NotBlank
* })
*/
private $title;
And the validator:
<?php
namespace AppBundle\Validator\Constraints;
use Symfony\Component\Validator\Constraints\Composite;
/**
* #Annotation
* #Target({"PROPERTY", "METHOD", "ANNOTATION"})
*
* #author Nicolas Brousse
*/
class ValidTranslation extends Composite
{
public $locales = array();
public $constraints = array();
public function getCompositeOption()
{
return 'constraints';
}
public function getRequiredOptions()
{
return array('locales', 'constraints');
}
}
<?php
namespace AppBundle\Validator\Constraints;
use Symfony\Component\Validator\Constraint;
use Symfony\Component\Validator\ConstraintValidator;
use Symfony\Component\Validator\Context\ExecutionContextInterface;
use Symfony\Component\Validator\Exception\UnexpectedTypeException;
/**
* #author Nicolas Brousse
*/
class ValidTranslationValidator extends ConstraintValidator
{
/**
* If property constraint
* {#inheritdoc}
*/
public function validate($value, Constraint $constraint)
{
if (!$constraint instanceof ValidTranslation) {
throw new UnexpectedTypeException($constraint, __NAMESPACE__.'\ValidTranslation');
}
if (false) { // #todo check by interface or trait
throw new UnexpectedTypeException($value, 'not a translation entity');
}
$context = $this->context;
$entity = $this->context->getObject();
if (in_array($entity->getLocale(), $constraint->locales)) {
$context = $this->context;
if ($context instanceof ExecutionContextInterface) {
$validator = $context->getValidator()->inContext($context);
$validator->validate($value, $constraint->constraints);
} else {
// 2.4 API
$context->validateValue($value, $constraint->constraints);
}
}
}
}
you form need to return 2 validations_groups, "Default" and the validation group corresponding to the "en" locale

Map PHP boolean to String t/f in Oracle

I'm refactoring an old application with an Oracle database using Symfony2 and Doctrine. I can't change the database scheme.
I need a boolean value in the model, but the database saves it as VARCHAR2(1 CHAR) with t or f. How can I access and write t/f on Oracle side and use it as boolean in Symfony?
Thanks!
Mitja
Like this in your entity:
/**
* #var string
*
* #ORM\Column(name="somefield", type="string", length=1)
*/
private $someField;
/**
* Set someField
*
* #param boolean $someField
* #return ...
*/
public function setSomeField(bool $someField)
{
$this->someField = 'f';
if($someField)
$this->someField = 't';
return $this;
}
/**
* Get someField
*
* #return boolean
*/
public function getSomeField()
{
if($this->someField == 't')
return true;
return false;
}

Symfony validation: First property constraint then class constraint

I'm using Symfony 2.5 and my Model class is the following:
/**
* #UserAssert\UserPasswordReset
*/
class ResetPassword {
/**
* #var string
* #Assert\NotBlank()
*/
public $username;
/**
* #var string
* #Assert\NotBlank()
* #Assert\Date
*/
public $birthday;
/**
* #var string
* #Assert\NotBlank()
*/
public $plainSecurityAnswer;
function __toString()
{
return $this->username . $this->birthday->format('Y-m-d H:i:s') . $this->plainSecurityAnswer;
}
}
This Model is mapped to a ResetFormType.
Now my intention: How can i say / configure, that i first want the property constraints to be passed. And if all property constraints are passed (e.g. no field is blank), i want the #UserAssert\UserPasswordReset to be called.
At the moment, it always validates the property AND the class constraints.
Regards ++
I think you can do it using a GroupSequence Validator like this:
/**
* #UserAssert\UserPasswordReset(groups={"PasswordReset"})
* #Assert\GroupSequence({"Default", "PasswordReset"})
*/
class ResetPassword
{
//----
}
In this mode UserPasswordReset will be validated only after the Defaults Asserts.
In the docs you will find some implementations example to use groups sequences..

Resources