read out value of protected property TYPO3\CMS\Core\DataHandling\DataHandler::$historyRecords - typo3

I'm updating a TYPO3 installation from v6 to v7 and have a problem with class TYPO3\CMS\Core\DataHandling\DataHandler
(https://typo3.org/api/typo3cms/class_t_y_p_o3_1_1_c_m_s_1_1_core_1_1_data_handling_1_1_data_handler.html).
I get the following error:
Fatal error: Cannot access protected property
TYPO3\CMS\Core\DataHandling\DataHandler::$historyRecords ...
caused by the following call
public function processCmdmap_afterFinish(&$data)
{
$dataChanged = $data->historyRecords;
Can anyone tell me how in TYPO3 v7 you can get the value of historyRecords?
Thanks in advance!!!

DataHandler::$historyRecords was not defined as property in TYPO3 6.2 but was implicitly set by class member access inside DataHandler (see DataHandler of 6.2). In TYPO3 7.6 the property has been declared the first time and defined to be protected.
The $historyRecords array could be seen as change pattern, containing the oldRecord and newRecord for a particular invocation of the DataHandler. This could be seen as contents of a RecordDataChangedEvent - which does not exist in that way in TYPO3, yet. The information is collected in DataHandler::compareFieldArrayWithCurrentAndUnset().
To get access to the information you have three possibilities in TYPO3 7.6:
Overload DataHandler by XCLASSing and provide a getHistoryRecords() method
XCLASSing is basically a bad principle since you can override functionality
that might be changed in upstream versions. In this case it would be "okay"
since you just provide a new getter-method that did not exist before
find more details in the XCLASS documentation
Use hooks to collect and determine changes on your own
processDatamap_preProcessFieldArray($incomingFieldArray, $table, $id, DataHandler $dataHandler)
processDatamap_postProcessFieldArray($status, $table, $id, $fieldArray, DataHandler $dataHandler)
collect differences in a singleton object comparing $incomingFieldArray to $fieldArray for a combination of $table and $id
this however leaves out possible version and shadowing interactions that have been applied to the field-array in between
Retrieve from database table sys_history
see DataHandler::setHistory() and do the reverse look-up
at the time when your processCmdmap_afterFinish hook is called, this data has been written already
look-up a combination of the following criteria from sys_history
tstamp equals $GLOBALS['EXEC_TIME']
tablename equals $table AND recuid equals $id
the field history_data contains then a serialized representation of $historyRecords

Related

Are setters mandatory in extbase models?

I am following this documentation: https://docs.typo3.org/m/typo3/book-extbasefluid/10.4/en-us/5-Domain/2-implementing-the-domain-model.html
The 'Organization' model defines setters and a method "addContact"
/**
* Adds a contact to the organization
*
* #param Person The contact to be added
* #return void
*/
public function addContact(Person $contact)
{
$this->contacts->attach($contact);
}
I created an extbase model myself, which requires records from an objectstorage. But i figured it out, that I could render records from an objectstorage in fluid, without defining "add{property}" and "set{property} methods. What are the purpose of these methods? When and where are they called?
Setter methods (and adder for ObjectStorages) are not needed by the framework. I'd recommend not adding them if you do not have the use case of setting a value programmatically.
Generally speaking you should not add code that you dont need.
Extbase itself will use reflection to gather and set properties that match database columns.
Setters are for fields that have a representation in the database.
You can add more properties to the models which are i.e. calculated or get the values somewhere else from that don't have setter methods.
Those properties you can access in fluid templates as long as they have also a declaration in the model.
Concerning the method addContact that's one property with probably 4 methods:
getContact (is singular but can have several)
setContact (is singular but can have several)
addContact (adds one contact to the $contact)
removeContact (removes one contact from the $contact)
So this property is still connected / related to the database, just that it's a foreign table as it's foreign model too.
$contact in your case is likely of type \TYPO3\CMS\Extbase\Persistence\ObjectStorage which is like an array iterable but just as object.

Extbase Repository objectType = NULL

We are migrating a 4.5 Extension to 7.2. One special case is strange. Trying to get a findOneByUid brings a "No class name was given to retrieve the Data Map for." Error.
Accessing via another object and using the DebuggerUtility it allows us to navigate to the object that fails, and there we can see, the objectType is NULL.
Any clue where to search? All the other objects can be accessed via findOneByUid.
How would you proceed to find the issue?
Adding the following lines solved the problem... any idea how to avoid this?
public function __construct() {
$this->objectManager = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance('TYPO3\\CMS\\Extbase\\Object\\ObjectManager');
$this->objectType = \TYPO3\CMS\Core\Utility\ClassNamingUtility::translateRepositoryNameToModelName($this->getRepositoryClassName());
}
The object type can only be null if the constructor of the repository has been overridden in a subclass without a call to the parent constructor. parent::__construct();
Instead of using the constructor, you should make use of the method initializeObject, which gets called after the constructor and which can safely be overridden.

symfony2 Argument 1 passed must implement interface Doctrine Collection, array given

I have a form that has 3 entites (Obras, FechaObra and HorarioObra) with one to many relationship. One Obra may have many FechaObra and one FechaObra may have many HorarioObra. but I made tha form as told in symfony.com/doc/current/cookbook/form/form_collections.html but it gives me this error:
Catchable Fatal Error: Argument 1 passed to Acme\ReservasBundle\Entity\FechaObra::setHorariosobra() must implement interface Doctrine\Common\Collections\Collection, array given, called in /var/www/html/grisar/entradas/vendor/symfony/symfony/src/Symfony/Component/PropertyAccess/PropertyAccessor.php on line 410 and defined
I already defined horariosobra as an arraycollection, but it keeps giving me that error.
The source code of the bundle is in: github.com/javiermarcon/tickets/tree/master/src/Acme/ReservasBundle
Does anyone know why is giving me that error?
Thanks
Remove strong typed \Doctrine\Common\Collections\Collection from setter method:
public function setHorariosobra($horariosobra)
{
// Be sure to "use" ArrayCollection class
$this->horariosobra = new ArrayCollection($horariosobra);
foreach ($horariosobra as $horarioobra) {
$horarioobra->setObra($this);
}
}
The should fix things. Remember, Forms component need not to know about Doctrine - it's entirely up to you to enforce usage of entities. Therefore, submitted data to setter method is generic array rather than Doctrine's Collection

Does symfony have a built-in method for comparing tainted values to the original?

I am using symfony 1.4 with Doctrine. I have built a form which uses a table that has the Versionable behaviour. As expected, Versionable creates a new version of the row every time the form is submitted and saved. My problem is that I would like to prevent it doing so if the actual values submitted are not any different from the original values put into the form via the edit action.
I know that I can do this with javascript relatively easily. I'm just curious as to whether symfony or Doctrine have this functionality already, and how it is used if so. It just seems like something that symfony would have a method for, which could be checked right before $form->save() is called. Am I dreaming or perhaps missing something obvious?
You can use the DoctrineRecord::getModified() function which returns an array of the modified fields and associated values from an overridden save() function or in a listener (preSave would be the best I guess).
If the new values are not any different, you can bypass the actual call to save(), so no new version is created.
The comment for the save() method of the Doctrine_Record is
/**
* applies the changes made to this object into database
* this method is smart enough to know if any changes are made
* and whether to use INSERT or UPDATE statement
*
* this method also saves the related components
*
* #param Doctrine_Connection $conn optional connection parameter
* #throws Exception if record is not valid and validation is active
* #return void
*/
so first, you should check whether it does not already work.
If not, Doctrine_Record has a isModified() method you could use. If the bind() method of the form object modifies the object in the form which should at first contain the default values, then this method should return true.
If you don't want to override save() method or implement a listener as jaudette suggested you can instead stay with form binding:
$form->bind($values);
if ($form->isValid()) {
$form->updateObject();
$changes = $form->getObject()->getModified();
// save to database if desired
$form->save();
}
The object will not be saved to database by calling $form->updateObject(), but the actual php object is changed.
Also note that you might have to call getModified() on each related object if you have embedded subforms.

What is the phpdoc syntax to link $this to a specific class in Aptana?

I'm working on Magento templates, but this issue would apply to any template loading system.
As these templates are loaded by the template engine there's no way for the IDE (in this case Aptana) to know what object type $this is.
Potentially it could more than one object as a single template could be loaded by multiple objects, but ignoring this, what would the correct phpdoc syntax be to specify a specific class for the $this object?
You can define it like this:
/* #var $this type */
where type is a class name
To be clear, using $this should only ever indicate an object of the current class, right?
PhpDocumentor doesn't currently (v1.4.3) recognize $this as a specific keyword that should equate to a datatype of the class itself.
Only datatypes known by PHP and classes already parsed by PhpDocumentor are the proper datatype values to use with the #return tag. There is a feature request in to have some option available in PhpDocumtentor to aid in documenting fluent methods that always "return $this". [1]
In the case of the #var tag, I don't see how it would be feasible for a class variable to contain its own class instance. As such, I can't follow what "#var $this" should be saying.
If, however, your intention with $this is not for fluent methods that "return $this", and was simply to be some shortcut to PhpDocumentor and/or your IDE to magically guess what datatypes you might mean by using $this, I'd have to guess there's no way to do it. The closest suggestion I could make would be to use the name of a parent class that is a common parent to all the various child classes that this particular var/return might be at runtime, and then use the description part of the tag to have inline {#link} tags that list out the possible child classes that are possible.
Example: I have a Parent abstract class with Child1, Child2, and Child3 children that each could occur in my runtime Foo class.
So, Foo::_var could be any of those child class types at runtime, but how would I document this?
/**
* #var Parent this could be any child of {#link Parent}, {#link Child1}, {#link Child2}, or {#link Child3}...
*/
protected $_var;
Getting back to the "return $this" issue, I'd document things in a similar way:
/**
* a fluent method (i.e. it returns this class's instance object)
* #return Parent this could be any child of {#link Parent}, {#link Child1}, {#link Child2}, or {#link Child3}...
*/
public function foo() {
return $this;
}
Documenting this way at least allows your class doc to have links to the particular classes. What it fails to do is highlight the fluent 'ness. However, if your IDE is capable of recognizing the class names, then perhaps it will be able to do the necessary logical linking to those other classes. I think Eclipse is able to do this at least with popup help, if you hover over the class name in the tag's description. I do not think Eclipse can use this to then make the various child classes' methods available in code completion. It would know about the Parent methods for code completion, because the datatype I explicitly list is Parent, but that's as far as the IDE can go.
[1] -- http://pear.php.net/bugs/bug.php?id=16223
I have found that defining a type with #var for $this does not work - presumably because $this is special and is treated as such by Aptana. I have a similar need to the poster I think - it is in template files (in my case simply located and included by functions within the data class) that I wish to set a type for $this. As #ashnazg says, setting a type for $this within a class definition is not needed, because the type of $this is always the type of the class (up to inheritance).
There is, however, a workaround for template files. At the top of the template file simply put something like
/**
* #var My_Data_Model_Type
*/
$dataModel = &$this;
Then simply use $dataModel (or whatever you choose to call it - maybe something shorter) instead of $this in the template