Symfony + Doctrine Oracle DateTime format issue - php

I have a problem with Oracle DateTime type in Symfony 2.7 + Doctrine.
I have a table with a DateTime column which is mapped in Symfony through Doctrine.
When I try to persiste the relative Entity I got the following error:
Could not convert database value "31-MAY-16 03.56.49.000000 PM" to Doctrine Type datetime. Expected format: Y-m-d H:i:s File: .../vendor/doctrine/dbal/lib/Doctrine/DBAL/Types/ConversionException.php Line: 63
I cannot change the default format in the Oracle Database.
I previously fixed the problem by modifing the method getDateTimeFormatString() in the vendor/doctrine/dbal/lib/Doctrine/DBAL/Platforms/OraclePlatform.php and it worked.
However, since I have to use Git and "composer install ..." in order to deploy my application in production environment, all vendors are installed from the Symfony repository; in that way I lose the changes I made in OraclePlatform.php
To solve the problem without touching the verdors libraries, i tried to set the following Oracle ENV variables on httpd init start script but it doesn't work
export NLS_TIME_FORMAT="HH24:MI:SS"
export NLS_DATE_FORMAT="YYYY-MM-DD HH24:MI:SS"
export NLS_TIMESTAMP_FORMAT="YYYY-MM-DD HH24:MI:SS"
export NLS_TIMESTAMP_TZ_FORMAT="YYYY-MM-DD HH24:MI:SS TZH:TZM"
I found a possible solution in the Known Vendor Issues in the Doctrine documentation about PostgreSQL where they suggest to use the VarDateTimeType by overriding the type like this:
use Doctrine\DBAL\Types\Type;
Type::overrideType('datetime', 'Doctrine\DBAL\Types\VarDateTimeType');
Type::overrideType('datetimetz', 'Doctrine\DBAL\Types\VarDateTimeType');
Type::overrideType('time', 'Doctrine\DBAL\Types\VarDateTimeType');
This seams to be the solution, however I have no idea on how to override the type with the code above but mostly where to put the above code.
Do someone have any idea?
Thanks
P.S. I'm using DateTime without timezone

Create a custom DBAL Type extending the DateTimeType and override the convertToPHPValue function (I copied the VarDateTimeType class, which couldn't successfully convert the Date type my Oracle installation was using):
<?php
namespace YourCompany\SomeBundle\Doctrine\DBAL\Types;
use Doctrine\DBAL\Platforms\AbstractPlatform;
use Doctrine\DBAL\Types\ConversionException;
use Doctrine\DBAL\Types\DateTimeType;
class SillyDateTimeType extends DateTimeType
{
/**
* {#inheritdoc}
* #throws \Doctrine\DBAL\Types\ConversionException
*/
public function convertToPHPValue($value, AbstractPlatform $platform)
{
if ($value === null || $value instanceof \DateTime) {
return $value;
}
$val = \DateTime::createFromFormat('d-M-y H.i.s.u A', $value);
if ( ! $val instanceof \DateTime) {
throw ConversionException::conversionFailed($value, $this->getName());
}
return $val;
}
}
Replace $val = \DateTime::createFromFormat('d-M-y H.i.s.u A', $value); with whatever format your installation is returning for those columns.
Then just register it under dbal in config.yml:
# app/config/config.yml
doctrine:
dbal:
types:
sillydatetime: YourCompany\SomeBundle\Doctrine\DBAL\Types\SillyDateTimeType
Now you can use sillydatetime (or whatever you call it) anywhere in your column type specifications.

I fixed the problem following the proposal of this comment in Github. In app/config/config.yml (Symfony 2.3.1) I added the following block:
services:
oracle.listener:
class: Doctrine\DBAL\Event\Listeners\OracleSessionInit
tags:
- { name: doctrine.event_listener, event: postConnect }

I don't know about Symfony/Doctrine, but this is simple to fix with the regular OCI functions:
$conn = oci_connect('username', 'password', 'connection_string');
// get the sysdate...
$select = oci_parse($conn, 'select sysdate from dual');
oci_execute($select);
print_r(oci_fetch_row($select));
// alter the session date format...
$alter = oci_parse($conn, 'alter session set NLS_DATE_FORMAT=\'YYYY-MM-DD HH24:MI:SS\'');
oci_execute($alter);
// get the sysdate again...
oci_execute($select);
print_r(oci_fetch_row($select));
This gives the output:
Array
(
[0] => 10-JUN-16
)
Array
(
[0] => 2016-06-10 13:39:34
)

Related

Overwrite Environment Variable Params with export BEHAT_PARAMS

I am trying to use environment-variable-behat-params to overwrite the following value in my YAML:
my_profile:
suites:
domain:
contexts:
- MyContext:
- my_config:
setting_setting: data
other_setting_setting: other_data
This is the export command:
export BEHAT_PARAMS='{"suites":{"domain":{"contexts":{"MyContext":{"my_config":{"my_setting":"on"}}}}}}'
And this is the PHP code:
/** #BeforeSuite */
public static function prepare(BeforeSuiteScope $scope) {
$my_settings = $scope->getEnvironment()
->getContextClassesWithArguments()['MyContext'][0];
if (isset($my_settings['my_setting']) && $my_settings['my_setting'] == 'on') {
//do something here
}
}
It seems to match the documentation, but my_setting remains off instead of being updated to on.
If I try to use a key which is at the root level of my_profile like this:
my_profile:
my_config:
setting_setting: data
With this is the export command:
export BEHAT_PARAMS='{"my_config":{"my_setting":"on"}}'
Then I get this error:
In ArrayNode.php line 311:
[Symfony\Component\Config\Definition\Exception\InvalidConfigurationException]
Unrecognized option "my_settings" under "testwork"
Exception trace:
Symfony\Component\Config\Definition\ArrayNode->normalizeValue() at /sites/scorecards/vendor/symfony/config/Definition/BaseNode.php:368
Symfony\Component\Config\Definition\BaseNode->normalize() at /sites/scorecards/vendor/symfony/config/Definition/Processor.php:35
Symfony\Component\Config\Definition\Processor->process() at /sites/scorecards/vendor/behat/behat/src/Behat/Testwork/ServiceContainer/ContainerLoader.php:81
Behat\Testwork\ServiceContainer\ContainerLoader->processConfig() at /sites/scorecards/vendor/behat/behat/src/Behat/Testwork/ServiceContainer/ContainerLoader.php:65
Behat\Testwork\ServiceContainer\ContainerLoader->load() at /sites/scorecards/vendor/behat/behat/src/Behat/Testwork/Cli/Application.php:185
Behat\Testwork\Cli\Application->createContainer() at /sites/scorecards/vendor/behat/behat/src/Behat/Testwork/Cli/Application.php:161
Behat\Testwork\Cli\Application->createCommand() at /sites/scorecards/vendor/behat/behat/src/Behat/Testwork/Cli/Application.php:122
Behat\Testwork\Cli\Application->doRun() at /sites/scorecards/vendor/symfony/console/Application.php:148
Symfony\Component\Console\Application->run() at /sites/scorecards/vendor/behat/behat/bin/behat:34
.. how can I fix this?
you just need to remove my_setting from your yaml file
because it super-cedes any environment variable
from the documentation link you provided
in order to specify a parameter in an environment variable, the value must not exist in your behat.yml

Class not found when creating a class with class name being a string

I need to create classes based on the parameter passed to a function. I do it this way:
public function index($source)
{
if(in_array($source, ModuleManager::getAllModules()))
{
$provider = new $source();
if($image)
{
return $provider->getAll(true);
}
else
{
return $provider->getAll(false);
}
}
}
Notice that on line 5 I'm trying to create an object of class $source which will definitely be available. I understand that the above code is actually an eval call. I'm using Laravel 5.2 and the above code returns:
FatalThrowableError in ProcReqController.php line 19:
Fatal error: Class 'Example' not found
In the above error Example can be any class that I made. Now if I hard code the value of $source then it works just fine.
What am I getting that error?
I believe what's happening is PHP gets confused when you try to instantiate a class whose class name is in a variable and it has to do with imports.
Solution 1
Set your $class variable to the fully qualified class name including the namespace and it should work.
In this way, new $class() should work even while including parenthesis.
Solution 2
After further testing, it seems when you instantiate a variable class, it always assumes global namespace.
With this in mind, you can use class_alias to alias each of your classes. In config/app.php, you can add each class to the aliases array.
'aliases' => [
....
'Example' => App\Example::class
]
The autoloader allows you to use classes without fully qualifying them... in the php interactive shell you'll have to manually include classes AND fully qualify them.
if you have a composer project, go to it's directory and do the following to load the Primal color classes:
set_include_path(getcwd().'/vendor/primal/color/lib/Primal/Color/');
include 'Color.php';
include 'Parser.php';
include 'RGBColor.php';
include 'HSVColor.php';
$hello = Primal\Color\Parser::parse('#666');
var_export($hello->toHSV());
/*
returns
Primal\Color\HSVColor::__set_state(array(
'hue' => 0,
'saturation' => 0,
'value' => 37.647058823529413,
'alpha' => 1,
))
*/
Remove the parentheses at the end of the instantiation call, I think.
Check out this php interactive shell session:
php > class Foo { };
php > $fooname = 'Foo';
php > $bar = new $fooname;
php > var_dump($bar);
object(Foo)#2 (0) {
}
src: https://stackoverflow.com/a/4578350/2694851

PHP, framework - Class must be declared abstract

I'm introducing to Phalcon, a php framework, by following the tutorial: https://docs.phalconphp.com/en/latest/reference/tutorial-rest.html
I'm facing with this problem: I have this error in the code below
class Robots must be declared abstract or implement methods
'getConnectionService(), setForceExists() etc..'
<?php
use Phalcon\Mvc\Model;
use Phalcon\Mvc\Model\Message;
use Phalcon\Mvc\Model\Validator\Uniqueness;
use Phalcon\Mvc\Model\Validator\InclusionIn;
class Robots extends Model{
public function validation()
{
// Type must be: droid, mechanical or virtual
$this->validate(
new InclusionIn(
array(
"field" => "type",
"domain" => array(
"droid",
"mechanical",
"virtual"
)
)
)
);
// Robot name must be unique
$this->validate(
new Uniqueness(
array(
"field" => "name",
"message" => "The robot name must be unique"
)
)
);
// Year cannot be less than zero
if ($this->year < 0) {
$this->appendMessage(new Message("The year cannot be less than zero"));
}
// Check if any messages have been produced
if ($this->validationHasFailed() == true) {
return false;
}
}
}
?>
And even if I try to execute an HTTP request i get:
Cannot instantiate abstract class Robots
Any ideas?
You probably didn't set your database service properly. Make sure that:
The service name is db (I've experienced problems changing the default services names)
You have set the db service in your main $di (some might instantiate another DI container and isolate the database service there)
Always use $di->setShared(...) for registering global services
Please provide more information and will be glad to help.

How to format date fields before save in CakePHP 3?

I used this in AppController:
Time::setToStringFormat('dd/MM/YYYY');
The date field in my form is a input type "text" to allow my user writes something like 31/12/2015.
However when I try to save (MySQL date) I get some errors of Time Class because inside the table the value now is 00-00-0000
Alunos Controller code
Thanks !
My final solution was this on bootstrap:
date_default_timezone_set('America/Sao_Paulo');
setlocale(LC_ALL, 'pt_BR', 'pt_BR.utf-8', 'pt_BR.utf-8', 'portuguese');
Type::build('time')->useImmutable();
Type::build('date')->useImmutable()->useLocaleParser();
Type::build('datetime')->useImmutable()->useLocaleParser();
Type::build('timestamp')->useImmutable();
\Cake\I18n\Time::setToStringFormat('dd/MM/yyyy HH:mm:ss');
\Cake\I18n\Date::setToStringFormat('dd/MM/yyyy');
\Cake\I18n\FrozenTime::setToStringFormat('dd/MM/yyyy HH:mm:ss');
\Cake\I18n\FrozenDate::setToStringFormat('dd/MM/yyyy');
\Cake\I18n\I18n::locale('pt-BR'); //new !
Type::build('decimal')->useLocaleParser();
Type::build('float')->useLocaleParser();
maybe this could help someone.
public function beforeSave($event, $entity, $options) {
$entity->dateField = date('Y-m-d', strtotime($entity->dateField));
}
If you are just creating a new application with a fresh database, delete does dates having 0000-00-00 and change the column definition so it can accept nulls. Using 0000-00-00 for dates is usually a really bad thing as only errors and bugs can come out of it :)
Edit based on the comments below
It seems like the problem was getting a string field to be parsed from the local date format to what php can understand. For this task you just need to configure the DateTimeType class to parse the dates using a locale-aware format as described here http://book.cakephp.org/3.0/en/orm/database-basics.html#parsing-localized-datetime-data
// In bootstrap.php or AppController or your controller action:
use Cake\Database\Type;
...
Type::build('datetime')->useLocaleParser();
You can also set the locale parser to parse a specific format. For the code above to work, make sure you set your application to use a locale:
I18n::locale('fr-FR')
Easy solution insert date format in CakePHP 3.x in Models and custom out views:
Insert ['rule' => ['date','dmy']]
Example
public function validationDefault(Validator $validator)
{
...
$validator
->add('demo_example_date', 'valid', ['rule' => ['date','dmy']]) //Format valid '30-12-2015' or '30-12-05'
->requirePresence('demo_example_date', 'create')
->notEmpty('factura_fecha');
...
return $validator;
}
Out view, set AppController
...
use Cake\I18n\Time;
use Cake\Database\Type;
Time::$defaultLocale = 'es-ES';
Time::setToStringFormat('dd-MM-YYYY');
Type::build('datetime')->useLocaleParser();
class AppController extends Controller
{
...
}
works for me using Postgres.
File config/app.php
in variable Datasources['default'] add command 'SET datestyle TO ISO, DMY' to init
'Datasources' => [
'default' => [
'init' => ['SET datestyle TO ISO, DMY '],
],
in mysql
https://my.vertica.com/docs/7.1.x/HTML/Content/Authoring/SQLReferenceManual/Statements/SET/SETDATESTYLE.htm

How to use Twig date to show week day in Chinese text?

I want to show the date format like: 10月09日, 周三 (which means 10/9, Wed.)
and my data is UNIX time like [message.time]: 1380813820000
so this is what I do in twig:
{{ (message.time/1000)|date("m月d日, 周w") }}
But it show me: 10月09日,周3, Because date "w" are numbers, not Chinese text.
so can I do anything by Twig to converse the text format?
thanks
The underlying problem is, that Twig uses the DateTime::format method, which does not support locales or (as far as I know) any other type of functionality to translate the names of the weekdays.
There are three solutions:
Use strftime, which supports locales (and thus localized weekday-names).
If you can use the intl extension of PHP, then you can use the Twig-extensions which comes with a intl extension for Twig.
You translate the weekdays by yourself.
Plus to use your preferred solution in a Twig-template, you have to extend the functionality of Twig.
Using strftime and setlocale
The following (rather large) code implements the strftime solution:
<?php
// inspired by phpdude:
// https://github.com/fabpot/twig/issues/378#issuecomment-4698225
class DateTimeHelper_Twig extends Twig_Extension
{
public function getFilters()
{
return array(
'datetime' => new Twig_Filter_Method($this, 'datetime',
array('needs_environment' => true)),
);
}
// This uses `strftime` which makes use of the locale. The format is not
// compatible with the one of date() or DateTime::format().
public function datetime(Twig_Environment $env, $date,
$format = "%B %e, %Y %H:%M", $timezone = null)
{
$date = twig_date_converter($env, $date, $timezone);
return strftime($format, $date->getTimestamp());
}
public function getName()
{
return 'DateTimeHelper';
}
}
$loader = new Twig_Loader_String();
$twig = new Twig_Environment($loader);
// Call the setlocale before you use the `datetime` in your templates.
// This only needs to be done once per request.
// If you already have a locale configured in your environment,
// you can replace this with setlocale(LC_TIME, ""); - that way the
// locale of your environment is used.
setlocale(LC_TIME, "zh_CN.UTF-8");
// Add the extension to Twig like that:
$twig->addExtension(new DateTimeHelper_Twig());
$message = array('time' => time() * 1000);
// use the `datetime` filter with %a which gets replaced by the short weekday name of
// the current locale.
echo $twig->render('{{ (message.time/1000)|datetime("%m月%d日, 周%a") }}',
array('message' => $message)), PHP_EOL;
This code shows 10月09日, 周三 on my system (after I installed the debian package locales-all ;-) ).
Of course, locales come with a list of restrictions you probably need to be aware of:
You have to use the correct locale (probably with UTF-8) and the locale you need has to be installed on all the systems which use your code.
Also this solution is not fully platform-independent (on windows setlocale works different/gives different results). Check out the PHP-manual of setlocale
It's easy to screw things up.
Using intl and the Twig-extensions
If you can use the intl extensions and the "Twig-extensions"-package, you have to use localizeddate instead of date:
// add the extension like that
$twig->addExtension(new Twig_Extensions_Extension_Intl());
$message = array('time' => time() * 1000);
echo $twig->render('{{ (message.time/1000)|localizeddate("none", "none", "zh", null, "MM月dd日, eee") }}', array('message' => $message)), PHP_EOL;
That code also shows 10月09日, 周三 - it even adds the 周-thingie automatically.
Of course, the date-format here is also different - check out the ICU user guide.
You can try this code if the setlocale function cannot working on you system.
<?php
require_once dirname(__FILE__).'/vendor/autoload.php';
$loader = new Twig_Loader_String();
$twig = new Twig_Environment($loader);
$twig->addFilter(new Twig_SimpleFilter('format_date', function($value) {
$weekdays = array('日','一','二','三','四','五','六');
return sprintf("%s, 周%s", date("m月d日"), $weekdays[date("w")]);
}));
echo $twig->render('{{ time_at | format_date }}', array(
'time_at' => 1380813820000/1000
));
I found a quick filter replace , here is the code snippet:
<div class="date"><span>{{ (create_time/1000)|date("m月d日,周D")|replace({'Mon':'一','Tue':'二','Wed':'三','Thu':'四','Fri':'五','Sat':'六','Sun':'日'}) }}</span></div>

Categories