Typo3/Extbase: LazyObjectStorage - access $fieldValue or $parentObject - typo3

I need to make some improvements to a Typo3-extension and have a question regarding the ObjectStorage.
TYPO3\CMS\Extbase\Persistence\Generic\LazyObjectStorage has the properties $parentObject and $fieldValue. Both are protected, no getter is defined in the class.
Is there any way to access the properties?
What I am trying to achieve:
class Topic extends AbstractEntity implements ... {
/**
* All users who have read this topic.
*
* #var \TYPO3\CMS\Extbase\Persistence\ObjectStorage<\Mittwald\Typo3Forum\Domain\Model\User\FrontendUser>
* #lazy
*/
protected $readers;
public function __construct($subject = '') {
// other stuff
$this->readers = new \TYPO3\CMS\Extbase\Persistence\ObjectStorage();
}
// more stuff
}
The corresponding column in the database holds an integer value, the property in the Model class is the ObjectStorage. I am not interested in the object, but in the integer value.
After initializing the ObjectStorage and populating, the properties are existing, but not accessible.
What to do? Thanks for input.

LazyObjectStorage extends \TYPO3\CMS\Extbase\Persistence\ObjectStorage and this class implements \Countable, so you can simply use count($this->readers) to get the size.

Related

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'.

TYPO3 : How to determine child-objecttypes of specific parent domain-model?

I have some different domain-models, each being parent of different sub-models.
All of those domain-models extend themselves out of a basic model class and I want to write a general function in the base-model, that deals with subclasses of the current model. Therefore, I need to find a way, to dynamically get all child-model-classes of a given domain-model.
Can this be done somehow ? Perhaps via Object-Storage-Definitions or similar ?!
Update : as mentioned in the comment section, mny question had nothing to do with TYPO3, it was a general php-question .. solution for my question are reflection-classes.
I guess your question has nothing to do with TYPO3, so take a look at this general PHP question thread and possible solutions here.
You are talking about Database Relationships. Yes, this can be done in TYPO3.
Each model should be mapped to a table. So, let's take for example the Category domain model and parent property
class Category extends AbstractEntity
{
/**
* #var \TYPO3\CMS\Extbase\Domain\Model\Category
*/
protected $parent = null;
/**
* #return \TYPO3\CMS\Extbase\Domain\Model\Category
*/
public function getParent()
{
if ($this->parent instanceof \TYPO3\CMS\Extbase\Persistence\Generic\LazyLoadingProxy) {
$this->parent->_loadRealInstance();
}
return $this->parent;
}
/**
* #param \TYPO3\CMS\Extbase\Domain\Model\Category $parent
*/
public function setParent(\TYPO3\CMS\Extbase\Domain\Model\Category $parent)
{
$this->parent = $parent;
}
The parent property will return the parent category. The same logic is when you want to get the childs.

using Class<?> to represent an interface

I hope the title accurately represents what I'm asking here. For my assignment here, I have a Speakerphone object, which is a singleton, and two interfaces, Listener and Talker with which Speakerphone needs to communicate.
There are two shoutMessage methods, the second of which takes a Class object as a parameter. Here's where I'm confused - I don't know if the "Class object" in the instructions is referring to the Listener interface, or the Speakerphone object. Can anyone tell me if the code in this method is correct, based on the instructions here?
public class Speakerphone extends Object {
private static Speakerphone sSpeaker = null;
private static HashSet<Listener> mListener = new HashSet<Listener>();
private static HashSet<Talker> mTalker = new HashSet<Talker>();
private Speakerphone() {
}
/*
* get
*
* #return the singleton instance of Speakerphone (Speakerphone)
*/
/************************************************
* ASSIGNMENT:
* Implement the get method
/************************************************/
public static Speakerphone get(){
if (sSpeaker == null){
sSpeaker = new Speakerphone();
}
return sSpeaker;
}
/*
* shoutMessage
*
* Sends the message to all of the Listeners tracked by Speakerphone
*
* #param talker a Talker whose message will be sent (Talker)
* #return nothing
*/
/************************************************
* ASSIGNMENT:
* Implement the shoutMessage method
/************************************************/
public void shoutMessage(Talker talker){
Iterator<Talker> talkIterator = mTalker.iterator();
while(talkIterator.hasNext())
talkIterator.next().getMessage();
}
/*
* shoutMessage
*
* Sends the message to all of the Listeners which are instances of
* the cls parameter
*
* #param talker a Talker whose message will be sent (Talker)
* #param cls a Class object representing the type which the Listener
* should extend from in order to receive the message (Class)
* #return nothing
*
* HINT: see Class.isAssignableFrom()
* http://docs.oracle.com/javase/7/docs/api/java/lang/Class.html#isAssignableFrom(java.lang.Class)
*/
/************************************************
* ASSIGNMENT:
* Implement the shoutMessage method
/************************************************/
public void shoutMessage(Talker talker, Class<?> cls){
if (Listener.class.isAssignableFrom(cls)){
Iterator<Talker> talkIterator = mTalker.iterator();
while(talkIterator.hasNext())
talkIterator.next().getMessage();
}
}
}
So, the class parameter in the shoutMessage method appears to be there so you can select out only listeners of a certain type. Class in Java is an object that describes a data type - a meta of meta so to speak.
Based on the comments in the code it looks like your shoutMessage method might be doing the opposite of what you want. Here's what I think it needs to do (based on the comments of the method):
Iterate through all of the listeners in your mListener HashSet. For each listener in the HashSet, do the following
As you iterate through, use Listener.class.isAssignableFrom to determine if the current listener is of class cls.
If it is of the type cls then call talker.getMessage() and pass that message to the current listener (by calling "receiveMessage" or "on" or whatever function is defined in your Listener interface).
If it is not of the type cls then ignore.

Add custom property to serialized object

I'm developing RESTful API for a web service. And I need to expose some properties that do not belong to an entity itself.
For example I have a Pizza entity object, it has it's own size and name properties. I'm outputting it in JSON format with FOSRestBundle and JMSSerializer. I've setup properties annotations for this entity to expose needed properties via serialization groups and it's working great.
But I need to add some properties that do not belong to the entity itself. For example I want my pizza to have property: isFresh that is determined by some PizzaService::isFresh(Pizza $pizza) service. How do I do this?
Should I inject some additional logic to serialization process (if so how)?
Should I create a wrapper entity with properties that I want to expose from original entity plus additional external properties?
Should I add property isFresh to the original Pizza entity and populate in in the controller before serialization?
Should I return additional data independent of entity data (in a sibling JSON properties for example)?
In other words: what are the best practices around this issue? Could you provide examples? Thank you.
I think you can do that with the VirtualProperty annotation :
/**
* #JMS\VirtualProperty
* #return boolean
*/
public function isFresh (){
...
}
Edit : another solution with the Accessor annotation
/** #Accessor(getter="getIsFresh",setter="setIsFresh") */
private $isFresh;
// ...
public function getIsFresh()
{
return $this->isFresh;
}
public function setIsFresh($isFresh)
{
$this->isFresh= $isFresh;
}
In your controller, you call the setIsFresh method
(See http://jmsyst.com/libs/serializer/master/reference/annotation)
I've decided to create my own class to serialize an entity.
Here's the example:
class PizzaSerializer implements ObjectSerializerInterface
{
/** #var PizzaService */
protected $pizzaService;
/**
* #param PizzaService $pizzaService
*/
public function __construct(PizzaService $pizzaService)
{
$this->pizzaService = $pizzaService;
}
/**
* #param Pizza $pizza
* #return array
*/
public function serialize(Pizza $pizza)
{
return [
'id' => $pizza->getId(),
'size' => $pizza->getSize(),
'name' => $pizza->getName(),
'isFresh' => $this->pizzaService->isFresh($pizza),
];
}
}
You just have to configure DC to inject PizzaService into the object serializer and then just call it like this from the controller:
$pizza = getPizzaFromSomewhere();
$pizzaSerializer = $this->get('serializer.pizza');
return $pizzaSerializer->serialize($pizza);
The object serializer will return an array that can be easily converted to JSON, XML, YAML or any other format by using real serializer like JMS Serializer. FOSRestBundle will do this automatically if you configured it so.

is it possible to override doctrine2 persistentobject magic getters and setting

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.