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

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.

Related

TYPO3 Extension: How to make a relation to another extension’s model optional?

I have an events extension (for TYPO3 9 LTS and 10 LTS), say MyVendor\MyEvents and a Locations extension, say MyVendor\MyLocations.
The Model MyVendor\MyEvents\Domain\Model\Events has a property eventLocation which is defined to be an object of MyVendor\MyLocations\Domain\Model\Locations.
Now I want to make the relation to MyVendor\MyLocations\Domain\Model\Locations optional. I have found a way for the TCA to show a different form field in the backend depending on the MyLocations extension being installed. But I have no idea how to make all the type definitions in the Events model conditional. They are crucial for the extension to work:
namespace MyVendor\MyEvents\Domain\Model
class Events extends \TYPO3\CMS\Extbase\DomainObject\AbstractEntity
{
/**
* #var \MyVendor\MyLocations\Domain\Model\Locations
*/
protected $eventLocation = NULL;
/**
* #return \MyVendor\MyLocations\Domain\Model\Locations $eventLocation
*/
public function getEventLocation()
{
return $this->eventLocation;
}
/**
* #param \MyVendor\MyLocations\Domain\Model\Locations $eventLocation
* #return void
*/
public function setEventLocation(\MyVendor\MyLocations\Domain\Model\Locations $eventLocation)
{
$this->eventLocation = $eventLocation;
}
}
In case MyVendor\MyLocations is loaded it needs to be defined as above, in case it isn’t loaded it should be just an integer.
In the TCA I am using if (TYPO3\CMS\Core\Utility\ExtensionManagementUtility::isLoaded('my_locations')) for showing a different field in the backend form for an event.
The Locations Model is in a separate extension because I am using it in a third extension as well.
In your events extension you could setup a repository for locations. Then you can map this repository to your location extensions model via TypoScript.

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

template for list view with system categories

I have an extbase extension (TYPO3 7) with a simple model of a contact person.
The person has a name and a picture.
So far this is clear.
But every Person has a category (e.g. where he works. Office, Marketing etc.)
Therefor i use the system categories, as described here:
https://wiki.typo3.org/TYPO3_6.0#Adding_categories_to_own_models_without_using_Extension_Builder
When creating a person via web > list, i can assign a category.
Now the question for templating:
If i debug my contact person, i get the output like screen below.
I want to have a list where every category (headline) is shown with it's contact persons.
How to do this?
Is the logic for this only in the template or also in the controller?
Has anybody an example for this?
Best regards
Markus
I guess the required logic you need is possible with Fluid with using the GroupedFor ViewHelper and many others. Because a person can have multiple categories this would become a huge nesting of Viewhelpers so I can not recommend to use Fluid for this even if its possible. This kind of logics belong to the controllers, models and repositories.
There are multiple ways to solve this logic. Here is an example how to realize this in the controller...
Controller:
/**
* #var \TYPO3\CMS\Extbase\Domain\Repository\CategoryRepository
* #inject
*/
protected $categoryRespoitory = NULL;
/**
* action list
* #return void
*/
public function listAction()
{
$allCategories = $this->categoryRespoitory->findAll();
$categoriesWithContacts = [];
/** #var \TYPO3\CMS\Extbase\Domain\Model\Category $category */
foreach($allCategories as $category) {
$contactsInCategory= $this->contactRepository->findByCategory($category);
if($contactsInCategory->count()>0) {
$categoriesWithContacts[] = [
'category' => $category,
'contacts' => $contactsInCategory
];
}
}
$this->view->assignMultiple([
'categoriesWithContacts' => $categoriesWithContacts
]);
}
Injecting the CategoryRespository will required clearing cache in install tool or reinstalling the extension.
Maybe you need this function in your ContactRepository:
/**
* #param \TYPO3\CMS\Extbase\Domain\Model\Category $category
* #return array|\TYPO3\CMS\Extbase\Persistence\QueryResultInterface
*/
public function findByCategory(\TYPO3\CMS\Extbase\Domain\Model\Category $category) {
$query = $this->createQuery();
return $query->matching($query->contains('categories', $category))->execute();
}
Then in Fluid you can do something like this:
<f:for each="{categoriesWithContacts}" as="categoryWithContact">
{categoryWithContact.category.title}
<f:for each="{categoryWithContact.contacts}" as="contact">
{contact.name}
</f:for>
</f:for>

Extbase update deleted=1 object in Controller fails (Object with identity x not found)

I want do give the function to 'restore' deleted Object in my FE-Ext. It seems, that it does not find any deleted records an so i cannot update them set deleted = 0.
What you be you sugestion to handle that from the controller?:
$query->getQuerySettings()->setIgnoreEnableFields(TRUE);
$query->getQuerySettings()->setIncludeDeleted(TRUE);
Thank you.
Im not quite sure what you mean by "from the controller". Normally you implement this in your repository and just call the method from the controller.
In your repo:
public function findRecordEvenIfItIsDeleted($uid) {
$query = $this->createQuery();
$settings = $query->getQuerySettings();
settings->setIgnoreEnableFields(TRUE);
settings->setIncludeDeleted(TRUE);
$query->matching($query->equals('uid', $uid));
return $query->execute();
}
In your controller:
$myObject = $this->myRepsository->findRecordEvenIfItIsDeleted($uid);
Done. (Of course your storage pid must be set (or disable respectStoragePage as well)
You're adding does not throw any error because you are setting the querySettings to include deleted records. But maybe, this setting has to be enabled even when you are updating, as the repository should find the object you are updating.
I haven't tested it but give this a try.
In your repository(just a pseudo code)
public function update($modifiedObject) {
settings->setIncludeDeleted(TRUE);
parent::update($modifiedObject);
}
I know this question was asked long time ago but today i had a similar problem with a hidden object. My solution was this one:
add this to your Model (in your case exchange "hidden" by "deleted"):
/**
* #var boolean
*/
protected $hidden;
/**
* #return boolean $hidden
*/
public function getHidden() {
return $this->hidden;
}
/**
* #return boolean $hidden
*/
public function isHidden() {
return $this->getHidden();
}
/**
* #param boolean $hidden
* #return void
*/
public function setHidden($hidden) {
$this->hidden = $hidden;
}
in your repository add this function to find the deleted/hidden object:
public function findHiddenByUid($uid) {
$query = $this->createQuery();
$query->getQuerySettings()->setIgnoreEnableFields(TRUE);
$query->getQuerySettings()->setEnableFieldsToBeIgnored(array('disabled','hidden'));
return $query
->matching($query->equals('uid', $uid))
->execute()
->getFirst();
}
now in your Controller you can read the object, set the "hidden" option and update it:
$yourobject = $this->yourobjectRepository->findHiddenByUid($uid);
$yourobject->setHidden(1);
$this->yourobjectRepository->update($yourobject);
Maybe not interesting for your task but for others:
In my case i additionally had the problem posting a hidden object in a form to an action. So note that if you want to post an object by a form, it is better (or probably necessary) to first set the objects deleted/hidden option to 0.

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.