is it possible to override doctrine2 persistentobject magic getters and setting - zend-framework

Can anybody tell me whether its posible to override doctrine2 persistentobject magic getters\setters? i'd like to do the below:-
public function setDob($dob)
{
$this->dob= new \Date($date);
}
however my entity is defined as:-
use Doctrine\Common\Persistence\PersistentObject;
use Doctrine\ORM\Mapping as ORM;
/**
* User
*
* #ORM\Table(name="user")
* #ORM\Entity(repositoryClass="Ajfit\Repository\User")
* #ORM\HasLifecycleCallbacks
*/
class User extends \Doctrine\Common\Persistence\PersistentObject
{
/**
* #var date $dob
*
* #ORM\Column(name="dob", type="date")
*/
protected $dob;
}
the public function setDob does not get called when I create the entity using:-
public function getNewRecord() {
return $this->metadata->newInstance();
}
I get the below error:-
Notice:- array to string conversion ...Doctrine\DBAL\Statement.php on line 98
Any help would be much apprieciated.
Thanks
Andrew

__call of PersistentObject#__call will not be called if you defined the setDob method.
What you're doing there is creating a new instance via metadata. What you are doing there is probably assuming that __construct or any setter/getter should be called by the ORM. Doctrine avoids to call any methods on your object when generating it via metadata/hydration (check ClassMetadataInfo#newInstance to see how it is done) as it does only know it's fields.
This allows you to be completely independent from Doctrine's logic.
About the notice, that is a completely different issue coming from Doctrine\DBAL\Statement, which suggests me that you have probably some wrong parameter binding in a query. That should be handled separately.

Related

Extend repository in TYPO3 9.5 LTS / Extbase

I'm trying to extend this IndexRepository to add my own method for a special search.
In the controller I inject my own IndexRepository with:
use Webian\Iancalendar\Domain\Repository\IndexRepository;
/**
* Inject index repository.
*
* #param IndexRepository $indexRepository
*/
public function injectIndexRepository(IndexRepository $indexRepository)
{
$this->indexRepository = $indexRepository;
}
What I did is working but I get this warning:
PHP Warning
Core: Error handler (BE): PHP Warning: Declaration of Webian\Iancalendar\Controller\
BackendController::injectIndexRepository(Webian\Iancalendar\Domain\Repository\IndexRepository $indexRepository)
should be compatible with HDNET\Calendarize\Controller\
AbstractController::injectIndexRepository(HDNET\Calendarize\Domain\Repository\IndexRepository $indexRepository)
in /typo3conf/ext/iancalendar/Classes/Controller/BackendController.php line 42
That's because I'm using my own Webian\Iancalendar\Domain\Repository\IndexRepository that extends HDNET\Calendarize\Domain\Repository\IndexRepository. If I use the original one the warning doesn't appear but obviously my own method is not called.
How can I avoid that warning?
You should either not extend HDNET\Calendarize\Controller\AbstractController but the default AbstractController of Extbase, then you will need to implement all required logic yourself.
Or you just use a different name for your injection method:
use HDNET\Calendarize\Controller\AbstractController;
use MyNamespace\MyExtension\Domain\Repository\IndexRepository;
class MyController extends AbstractController
{
...
/**
* The index repository.
*
* #var IndexRepository
*/
protected $myIndexRepository;
/**
* Inject index repository.
*
* #param IndexRepository $myIndexRepository
*/
public function injectMyIndexRepository(IndexRepository $myIndexRepository)
{
$this->myIndexRepository = $myIndexRepository;
}
...
class IndexRepository extends \HDNET\Calendarize\Domain\Repository\IndexRepository
{
...
// My method that extends \HDNET\Calendarize\Domain\Repository\IndexRepository functionalities
public function findByStartDate(DateTime $startDate = null, DateTime $endDate = null)
{
...
The method name does not really matter, only that it starts with inject and has a type hint indicating the dependency to inject.

Virtual properties in TYPO3 extbase domain models?

I'm trying to use a virtual domain model property in TYPO3 9.5.x that doesn't have a database field representation but I can't get it to work.
My model looks like this
class Project extends \TYPO3\CMS\Extbase\DomainObject\AbstractEntity {
/**
* participants
*
* #var string
*/
protected $participants;
...
/**
* Returns the participants
*
* #return string $participants
*/
public function getParticipants()
{
$this->participants = "foo";
return $this->participants;
}
}
I do see the property when I debug the model but it's always null as if it doesn't even recognise the getter method getParticipants().
Any idea what I might be doing wrong?
Already added a database field to ext_tables.sql and the TCA, but it didn't seem to make a difference.
The property is null because that's the state when the Extbase debugger inspects it. Notice that the Extbase debugger knows nothing about getters and also does not call them.
So if you want to initialize your property you must do this at the declaration time:
protected $participants = 'foo';
You can debug this property by simpy accessing it.
In Fluid, if you use <f:debug>{myModel}</f:debug>, you will see NULL for your property.
But if you directly use <f:debug>{myModel.participants}</f:debug>, you will see 'foo'.

PHP strict_types and relation to invisible TYPO3-record

A property of the model is a relation to one other record like this:
/**
* #var \MyCompany\MyExtension\Domain\Model\OtherObject
*/
public $otherObject;
/**
* #return OtherObject
*/
public function getOtherObject(): OtherObject
{
return $this->otherObject;
}
Now, assume the connected object to be invisible (e.g. it's hidden or time-restricted). Extbase is trying to assign 0, but PHP expects an instance of OtherObject... Bam! - you get an error.
How to deal with that? Hidden or time-restricted records are not uncommon.
You either need to require PHP 7.1 and use a nullable return type hint like ?OtherObject or remove the type hint completely for now. In any case you cannot rely on something being returned here so your consuming code needs to handle this.

SphinxQL & Phalcon\Mvc\Model

I have a Sphinx search engine running on MySQL protocol and I use Phalcon\Db\Adapter\Pdo\Mysql to connect to it. Sphinx tables are implemented as models.
When I try to select (using SpinxQL) I, obviously, get an error when database adapter attempts to extract table metadata running queries against tables which are not supported and not present respectively in SpinxQL. There is a workaround in the documentation showing how to manually assign metadata... But being to lazy by nature I want to try to automate metadata generation.
I assume that metadata is produced by the database adapter, probably as a result of calling getColumnsList() on the instance following getColumnDefinition() or something else (???). Is this my assumption correct? I want is to extend Phalcon\Db\Adapter\Pdo\Mysql and override those methods to be compatible with Sphinx.
Thanks in advance for your suggestions!
Ok, you need to override at least two methods to make this work, the following class would work:
<?php
class SphinxQlAdapter extends Phalcon\Db\Adapter\Pdo\Mysql implements Phalcon\Db\AdapterInterface
{
/**
* This method checks if a table exists
*
* #param string $table
* #param string $schema
* #return boolean
*/
public function tableExists($table, $schema=null)
{
}
/**
* This method describe the table's columns returning an array of
* Phalcon\Db\Column
*
* #param string $table
* #param string $schema
* #return Phalcon\Db\ColumnInterface[]
*/
public function describeColumns($table, $schema=null)
{
}
}
Then in your connection, you use the new adapter:
$di->set('db', function(){
return new SphinxQlAdapter(
//...
);
});

Symfony/Doctrine: "Catchable Fatal Error: Object of class <type> could not be converted to string" when persisting

A symfony2 application has a Job entity that has as a property of type WebSite.
A simplified representation of this without other properties or methods:
/**
* #ORM\Entity
* #ORM\Table(name="Job")
*/
class Job
{
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* #ORM\Column(type="integer", name="website_id", nullable=false)
* #ORM\ManyToOne(targetEntity="Example\ExampleBundle\Entity\WebSite")
*/
protected $website;
}
Symfony/Doctrine is trying to cast the website property to a string when persisting resulting in the error:
Catchable Fatal Error: Object of class
Example\ExampleBundle\Entity\WebSite could not be converted to string
in /vendor/doctrine/dbal/lib/Doctrine/DBAL/Statement.php line 131
I believe the above #ORM\Column annotation denotes the website property to be an integer. I don't understand why Symfony/Doctrine wishes to try and convert the website property to a string.
Non-ideal workarounds I have tried in an attempt to resolve the matter:
Adding __toString() method to WebSite, returning a string representation of the id property, causes the correct value to ultimately end up in the Job.website_id datafield; this workaround is impractical as I will in the future need __toString() to be available to present a string elsewhere in the application.
Removing the #ORM\Column annotation from the website property; this results in all future diff-generated migrations (php app/console doctrine:migrations:diff) removing the 'not null' aspect of the relevant database field.
Are there any changes I should make to the above annotation to inform Symfony/Doctrine to call the getId() method of WebSite to get what it needs when persisting? Are there any changes I could make to WebSite to achieve the same?
What changes are required to ensure that the above annotation can remain in place such that Doctrine ultimately calls WebSite.getId() to get what it needs when persisting instead of trying to cast the object to a string?
You have to remove the #ORM\Column(type="integer" annotation from the $website property.
To be sure that the website_id column keeps the NOT NULL constraint, add a JoinColumn annotation with nullable=false in it:
/**
* #var Example\ExampleBundle\Entity\WebSite
*
* #ORM\ManyToOne(targetEntity="Example\ExampleBundle\Entity\WebSite")
* #ORM\JoinColumn(name="website_id", referencedColumnName="id", nullable=false)
*/
protected $website;