'How do I setup Birthdates using Yii3 and its Cycle-ORM integration?
Preconditions
- mySql database client_birthdate field set as DATE and nullable if user does not enter date.
- User inputs Client's Birthdate on __form textbox as a string in mySql format YYYY/MM/DD or not.
- Yii3's ClientForm gets the string or empty string and converts to DATETIME so that Cycle Orm can process it.
- Yii3's ClientService saves the date using Cycle's Client Entity's getter and setter methods and annotations.
- Php 7.4.9
- Typed property. Previously php allowed this variable declaration below a class
public $var;
now inserting typed property between public and $var iepublic ?string $var = ''
excludes other types. Question mark before type allows for null value input. So only two alternatives. - Understanding mySql's '0000-00-00' for non date input.
- Download fork of https://github.com/yiisoft/yii-demo
dateHelper.php (adapted from Invoiceplane)
/**
* @return string|null
*/
public function date_from_mysql($date, $s)
{
//if previous input was not a date mySql would have input '0000-00-00'
if ($date <> '0000-00-00') {
//CYCLE converts all dates to DateTimeImmutable
$date = DateTime::createFromImmutable($date);
//$date = DateTime::createFromFormat('Y-m-d', $date);
//eg. $date->format('Ymd')
return $date->format($s->setting('date_format'));
}
return $date;
}
return '';
}
__form.php caption
<div class="mb-3 form-group has-feedback">
<label form-label for="client_birthdate"><?= $s->trans('birthdate'); ?></label>
<?php
$bdate = $body['client_birthdate'] ?? null;
if ($bdate && $bdate != "0000-00-00") {
//use the DateHelper
$datehelper = new DateHelper();
$bdate = $datehelper->date_from_mysql($bdate, false, $s);
} else {
$bdate = null;
}
?>
<div class="input-group">
<input type="text" name="client_birthdate" id="client_birthdate" placeholder="1900/12/01"
class="form-control data-datepicker"
value="<?= Html::encode($bdate); ?>">
<span class="input-group-addon">
<i class="fa fa-calendar fa-fw"></i>
</span>
</div>
</div>
Entity/Client.php
declare(strict_types=1);
namespace App\Invoice\Entity;
use \DateTime;
/**
* @Entity(
* repository="App\Invoice\Client\ClientRepository",
* mapper="App\Invoice\Client\ClientMapper",
* constrain="App\Invoice\Client\Scope\activeScope"
* )
* @Table(
* indexes={
* @Index(columns={"client_active"}),
* }
* )
*/
class Client
{
/**
* @Column(type="date", nullable=true)
*/
private $client_birthdate = '';
//CYCLE converts all date formats ie. DATE, DATETIME, to DateTimeImmutable so
work with DateTimeImmutable
public function __construct($client_birthdate = '')
public function getClient_birthdate() : ?DateTimeImmutable
{
if (isset($this->client_birthdate) && !empty($this->client_birthdate)){
return $this->client_birthdate;
}
if (empty($this->client_birthdate)){
return $this->client_birthdate = null;
}
}
public function setClient_birthdate(?\DateTime $client_birthdate): void
{
$this->client_birthdate = $client_birthdate;
}
Client/ClientForm.php
declare(strict_types=1);
namespace App\Invoice\Client;
use Yiisoft\Form\FormModel;
use Yiisoft\Validator\Rule\Required;
use \DateTimeImmutable;
use \DateTime;
final class ClientForm extends FormModel {
private ?string $client_birthdate = null;
public function getClient_birthdate(): ?\DateTime
{
if (isset($this->client_birthdate) && !empty($this->client_birthdate)){
return new DateTime($this->client_birthdate);
}
if (empty($this->client_birthdate)){
return $this->client_birthdate = null;
}
}
Client/ClientService
<?php
declare(strict_types=1);
namespace App\Invoice\Client;
use App\Invoice\Entity\Client;
use App\User\User;
final class ClientService
{
private ClientRepository $repository;
public function __construct(ClientRepository $repository)
{
$this->repository = $repository;;
}
public function saveClient(User $user, Client $model, ClientForm $form): void
{
$model->setClient_birthdate($form->getClient_birthdate());
Solution 1:[1]
Things to look out for:
- Ensure _form 'id' and 'name' values eg. client_birthdate correspond to Entity @column and Database tables fields. ie Use field names consistently through Entity, Annotations. The ClientForm's getter method will receive data from the __form which is a string or null. The getter will convert this to a DATETIME or null so that CYCLE ORM (Spiral Framework) can process it.
- Ensure initialization in Entity/Client.php instantiation area ie. BEFORE construct and IN construct.
Tips
- Annotations above function are read by Cycle's annotations.
use \DateTime;
before Annotations. Don't forget backslash to indicate DateTime is a php class not in current Namespace.- mySql type DATE in database and 'date' included in annotation below. ie.
* @Column(type="date", nullable=true)
otherwise Cycle will not be able to read it. - I have elected to use a simple untyped, nullable string.
.../Entity/Client.php
public function getClient_birthdate() : ?\DateTimeImmutable
and
public function setClient_birthdate(?\DateTime $client_birthdate): void
...src/Invoice/Entity/Client.php...
/**
* @Column(type="date", nullable=true)
*/
private $client_birthdate = '';
- The value accepted from coalface __form uses a string so initialize ClientForm.php's
private ?string $client_birthdate = null
with a string not a DateTime function. - Question mark before ?\DateTime allows for null value. Use consistently in function declaration as well as seen below.
...src/Invoice/Client/ClientForm.php
public function getClient_birthdate(): ?\DateTime
{
if (isset($this->client_birthdate) && !empty($this->client_birthdate)){
return new DateTime($this->client_birthdate);
}
if (empty($this->client_birthdate)){
return $this->client_birthdate = null;
}
}
The above code can be reduced to:
public function getClient_birthdate() : ?\DateTime
{
// convert the input string on the form received by means of '$this->client_birthdate'
// back into DateTime so that Cycle can deal with it and
// save it in 'date' format in mysql behind the scenes
return new DateTime($this->client_birthdate);
}
Solution 2:[2]
INVOICEPLANE SOLUTION
A Database Error Occurred Error Number: 1525 Incorrect DATE value: '0000-00-00' fix error 58 El error se debe al modo sql, que puede ser un modo estricto
solution permanent to Incorrect DATE value: '0000-00-00' change thsis data example > 1970-01-01
invoiceplane/application/modules/invoices/models/Mdl_invoices.php
or temporal solution mysql SET GLOBAL sql_mode = '';
ubuntu 20.04 mysql 8
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | |
Solution 2 | user11506071 |