[TYPO3-mvc] Repository with external database

Stephan Schuler Stephan.Schuler at netlogix.de
Wed Oct 2 13:54:46 CEST 2013


Hi Henk.


I would suggest to not create completely new classes but to extend the existing ones.

And: I would only change the Typo3DbBackend class.

Just create your very own Typo3DbBackend class that extends the original one. This way you keep the original code in place as long as you don't overwrite methods.
It's a Singleton, so you need to specify which one gets used -- and cannot simply use your own in one extension and the default in another. That's a little bit of a pity, but that's the way it is.

So, extend the original one and provide TypoScript which tells each and everything to use your Typo3DbBackend instead of the original one.

Here you have the method getObjectDataByQuery() method. It gets a query object and returns the raw database result array. Here's the point to intercept.
You need to investigate on the provided Query object. If it targets your own database, then you need to handle the query yourself. How to do so is pretty much the default content of getObjectDataByQuery.

Maybe it's enough to adjust the $this->link property in the first line of getObjectByDataQuery to point to the other database, then let parent::getObjectDataByQuery() process and turn the $this->link property back right after that.
This clearly requires to have a compatible layout. But you didn't point out if that's a problem to you. So I suggest it is not.

If the provided Query object does not affect your other database, then I would just go on calling parent::getObjectDataByQuery() and return its result immediately.


Just like this:
> class MyRemoteBackend extendsd Typo3DbBackend {
>       public function getObjectDataByQuery(Tx_Extbase_Persistence_QueryInterface $query) {
>               $originalLink = $this->link;
>               if ($this->queryTargetRemoteDatabase($query) {
>                       $this->link = $this->remoteDatabaseLink;
>               }
>               $result = parent::getObjectDataByQuery(query);
>               $this->link = $originalLink;
>               return $result;
>       }
> }

As I told you, this requires the remote database to be a compatible mysql database at the one hand and requires your query to have no join or subselect affecting both of your databases.

This code might have changed on 6.1 where the core switched from mysql to mysqli. So it could be a little different. But that's not so much code, so I think I made my point.


Regards,



Stephan Schuler
Web-Entwickler

Telefon: +49 (911) 539909 - 0
E-Mail: Stephan.Schuler at netlogix.de
Website: media.netlogix.de

-----Ursprüngliche Nachricht-----
Von: typo3-project-typo3v4mvc-bounces at lists.typo3.org [mailto:typo3-project-typo3v4mvc-bounces at lists.typo3.org] Im Auftrag von Henk Scholten
Gesendet: Mittwoch, 2. Oktober 2013 13:22
An: typo3-project-typo3v4mvc at lists.typo3.org
Betreff: Re: [TYPO3-mvc] Repository with external database

Hello Stephan,

Thanks for your reaction.
I prefer the clean way :-)
However, i'm struggeling with the StorageBackend.
Can you please give me a hint?

Classes\Extbase\Persistence\Backend.php

<?php
namespace Ws\FfPersons\Extbase\Persistence\BackendInterface;

class Backend implements
\TYPO3\CMS\Extbase\Persistence\Generic\Storage\BackendInterface,
\TYPO3\CMS\Core\SingletonInterface {
        // which methods should i call here and how should they look like?
}
?>

Classes\Domain\Repository\PersonRepository.php

<?php
namespace Ws\FfPersons\Domain\Repository;

class PersonRepository extends \TYPO3\CMS\Extbase\Persistence } ?>

Classes\Domain\Model\Person.php

<?php
namespace Ws\FfPersons\Domain\Model;

class Person extends \TYPO3\CMS\Extbase\DomainObject\AbstractEntity {
        // all getters and setters
}
?>

Configuration\TypoScript\setup.ts

plugin.tx_ffpersons {
        persistence {
                classes {
                        Ws\FfPersons\Domain\Model\Person {
                                mapping {
                                columns {
                                        titles.mapOnProperty = titels_voor
                                }
                        }
                }
        }
}

config.tx_extbase {
        features.rewrittenPropertyMapper = 1
        objects.TYPO3\CMS\Extbase\Persistence\Generic\BackendInterface.className = Ws\FfPersons\Exbase\Persistence }

Regards,
Henk

Op 01-10-13 18:48, Stephan Schuler schreef:
> Hi Henk.
>
>
> Well, you're wrong. Something between "slightly" and "completely", unfortunately.
>
>
> There are several other things involved. You have the PersistenceManager, the PersistenceBackend and some query stuff. All of them are involved when a Repository tries to determine certain database rows.
>
> The Repository uses a Query to fetch objects.
> The Query calls the PersistenceManager.
> The PersistenceManager calls the PersistenceBackend.
> The PersistenceBackend calls the StorageBackend.
>
> The StorageBackend triggers the SQL queries against the database through t3lib_DB, so it returns raw arrays.
>
> Then the StorageBackend passes this array to the PersistenceManager.
> The PersistenceManager passes this array to the Query.
>
> The Query uses this array as parameter for a QueryResult.
> Usually here the stack stops and postpones further execution until real access to the records is done, such as looping "foreach" or something.
>
> The QueryResult calls the DataMapper to Extbase-Entities out of those raw arrays.
>
>
> So, what to do depends on the amount of work you want to spend, how clean you want it to be and how complex your model is.
>
>
> You could call the database just like you did in your example. But instead of creating the objects yourself by looping over the $row result, you should use the DataMapper here. It makes sure to have necessary transformations applied, such as \DateTime objects where the database returns integers or something.
> But keep in mind: This method prevents you from using magic methods, such as "findBy.*()". If your model has a property "title", you can simply call the repository "findByTitle($title)" or "findOneByTitle($title)", then you will get either all or one that match the given title -- but that of course doesn't apply to your very own database which only gets used by findAll. Even the "findByUid" isn't covered here.
>
>
> The most clean way would be to use a different StorageBackends here.
>
> Usually Extbase uses the Typo3DbBackend. Have a look at the method "getObjectDataByQuery". This one fetches the statement from the query, replaces properties (such as $title in the example above), takes care of quoting them.
> So you could just extend the Typo3DbBackend and overwrite the getObjectDataByQuery method. If your external database provides compatible schema, you could even try to temporarily replace the internal $databaseHandle property of your very own version ofthe extended Typo3DbBackend.
>
> This of course doesn't play well with SQL joins and stuff, so you must take care of relations yourself. But if you stick to lazy loading wherever you can, this might be achievable, too.
>
>
> Regards,
>
>
> Stephan Schuler
> Web-Entwickler
>
> Telefon: +49 (911) 539909 - 0
> E-Mail: Stephan.Schuler at netlogix.de
> Website: media.netlogix.de
>
>
>
> --
> netlogix GmbH & Co. KG
> IT-Services | IT-Training | Media
> Neuwieder Straße 10 | 90411 Nürnberg
> Telefon: +49 (911) 539909 - 0 | Fax: +49 (911) 539909 - 99
> E-Mail: info at netlogix.de | Internet: http://www.netlogix.de
>
> netlogix GmbH & Co. KG ist eingetragen am Amtsgericht Nürnberg (HRA
> 13338) Persönlich haftende Gesellschafterin: netlogix Verwaltungs GmbH
> (HRB 20634)
> Umsatzsteuer-Identifikationsnummer: DE 233472254
> Geschäftsführer: Stefan Buchta, Matthias Schmidt
>
>
>
> -----Ursprüngliche Nachricht-----
> Von: typo3-project-typo3v4mvc-bounces at lists.typo3.org
> [mailto:typo3-project-typo3v4mvc-bounces at lists.typo3.org] Im Auftrag
> von Henk Scholten
> Gesendet: Dienstag, 1. Oktober 2013 10:50
> An: typo3-project-typo3v4mvc at lists.typo3.org
> Betreff: [TYPO3-mvc] Repository with external database
>
> Hello,
>
> I'm pretty new to extbase ans was wondering if this is the right way to to call an external database in my repository and put the results in the model with extbase:
>
> <?php
> namespace Ws\FfPersons\Domain\Repository;
>
> class PersonRepository extends
> \TYPO3\CMS\Extbase\Persistence\Repository {
>
>          public function initializeObject() {
>                  $this->conf =
> unserialize($GLOBALS['TYPO3_CONF_VARS']['EXT']['extConf']['ff_persons']);
>                  $this->db =
> \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance('TYPO3\\CMS\\Core
> \\Database\\DatabaseConnection');
>
>                  try {
>                          $this->db->setDatabaseHost($this->conf['hostname']);
>                          $this->db->setDatabaseUsername($this->conf['username']);
>                          $this->db->setDatabasePassword($this->conf['password']);
>                          $this->db->sql_pconnect();
>                  } catch (\TYPO3\CMS\Fluid\Core\ViewHelper\Exception $exception) {
>                          throw new
> \TYPO3\CMS\Fluid\Core\ViewHelper\Exception($exception->getMessage());
>                  }
>
>                  try {
>                          $this->db->sql_select_db($this->conf['database']);
>                  } catch (\TYPO3\CMS\Fluid\Core\ViewHelper\Exception $exception) {
>                          throw new
> \TYPO3\CMS\Fluid\Core\ViewHelper\Exception($exception->getMessage());
>                  }
>          }
>
>          /**
>           * findAll
>           *
>           * @return
>           */
>          public function findAll() {
>                  $select = array();
>                  $select['fields'] = '*';
>                  $select['table'] = 'persons';
>                  $select['where'] = '';
>                  $select['groupby'] = '';
>                  $select['orderby'] = 'surname';
>                  $res = $this->db->exec_SELECTquery($select['fields'],
> $select['table'], $select['where'], $select['groupby'],
> $select['orderby']);
>
>                  $persons = array();
>                  while ($rw = $this->db->sql_fetch_assoc($res)) {
>                          $personObj = new \Ws\FfPersons\Domain\Model\Person;
>                          $personObj->setFullname($rw['naam_volledig']);
>                          $personObj->setNickname($rw['roepnaam']);
>                          $persons[] = $rw;
>                  }
>
>                  return $persons;
>          }
>
> }
> ?>
>
> I read something about an persistence layer but don't know how to use that.
>
> All suggestions are welcome!
>
> Regards,
> Henk
> _______________________________________________
> TYPO3-project-typo3v4mvc mailing list
> TYPO3-project-typo3v4mvc at lists.typo3.org
> http://lists.typo3.org/cgi-bin/mailman/listinfo/typo3-project-typo3v4m
> vc
>

_______________________________________________
TYPO3-project-typo3v4mvc mailing list
TYPO3-project-typo3v4mvc at lists.typo3.org
http://lists.typo3.org/cgi-bin/mailman/listinfo/typo3-project-typo3v4mvc


More information about the TYPO3-project-typo3v4mvc mailing list