How to handle large QueryResults in TYPO3 - typo3

If I try to iterate trough a QueryResult with a lot of relations, my foreach loop needs a lot of time.
/** #var Product $productItem */
foreach ($products as $productItem) {
print($productItem->getTitle());
}
How can I do it the fast way?
Thanks in advance

You can annotate relations in every model with #lazy which will save you alot of time. After adding #lazy annoation you have to clear the cache in the install tool or reinstall the extension to take effect.

Related

Manage many to many relations in FosRest Bundle

I am using FosRest Bundle with symfony and I have a many to many relations between two tables.
For example:
class Site
{
/** ManyToMany **/
protected $languages;
}
class Language
{
/** ManyToMany **/
protected $sites;
}
I had records previously saved in each table separately but now I want to add relations between them in my new table site_language but I am not sure how to do it.
In SiteController I have these methods:
getSitesAction()
getSiteAction()
postSiteAction()
putSiteAction()
patchSiteAction()
deleteSiteAction()
Should I create a new method like postSiteLanguagesAction()?
Or modify the existing postSiteAction()?
Sort answer: probably both, kinda.
There are two separate concerns here:
altering the languages, that the site has ... though, I probably would just call it postLanguagesAction() instead
adding new sites
There are are actually two other methods, taht you forgot about: putSiteAction() and patchSiteAction() (TBH, I am not sure why you support both). When you update the existing site configuration, you will also need to have an ability to update its available language set.
P.S.
Regarding names, since you controller is most likely already called "Sites", I would have called the methods postResourceAction(), getResourceAction(), getCollectionAction(), etc., because it is kinda hard to see the difference between "posts" and "post" at a glance. And it would also make the "specialized methods" more noticeable.

Symfony/Doctrine: Entity "schema" annotation not environment dependent?

I am having trouble with getting functional tests to run in Symfony3 with Doctrine.
I have the code organized in two bundles with which need to be accessed by one EntityManager with entities stored in two different MySQL databases.
To achieve this, all Entities have a "schema" annotation in their definition, like this:
/**
* #ORM/Table(name="tablename", schema="schema")
* #Entity( ... )
*/
Without this setting, it has been my experience, that the Doctrine schema:create tool is not able to correctly create the entities in the right databases.
However it appears, that the schema annotation is not considered to be environment dependent.
So when I want to run functional tests that need to load fixtures, the ORMPurger tries to purge schema.tablename, where it should use the table/schema "test_schema".
Is there any way to keep the schema annotation but make it dependent on the environment, so that when the environment is "test", a different schema is used?
EDIT:
It appears that using the "schema" annotation for entities is pretty terrible all around when you are using different Symfony environments. At least when used in conjunction with MySQl, at least I think that that is the reason, since MySQL doesn't actually support schemas.
Every Symfony or Doctrine command I tried to take the schema annotation literally, regardless of the --env setting.
I've done some more digging and found what I needed to do perfectly laid out here:
Programmatically modify table's schema name in Doctrine2?
So I added an EventListener, that adds the correct schema according to the EM used so I don't need hard-coded schema annotations anymore.
Heres the code for the Listener I've made:
<?php
namespace /* ... */
use Doctrine\ORM\Mapping\ClassMetadata;
use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\Event\LoadClassMetadataEventArgs;
class MappingListener
{
public function loadClassMetadata(LoadClassMetadataEventArgs $eventArgs)
{
/** #var EntityManagerInterface $entityManager */
$entityManager = $eventArgs->getEntityManager();
/** #var ClassMetadata $classMetadata */
$classMetadata = $eventArgs->getClassMetadata();
$database = $entityManager->getConnection()->getDatabase();
$classMetadata->table['schema'] = $database;
}
}

Access Repository from Resource folder

I have a Typo3 Extension (Typo3 CMS 6.2) and I want to access the repository globalSettingsRepository from a PHP file which is located in /Resource/PHP/.
The dependency injection does not work although I cleared the cache:
/**
* globalSettingsRepository
*
* #var \TYPO3\Institutsvideoverwaltung\Domain\Repository\GlobalSettingsRepository
* #inject
*/
public $globalSettingsRepository = NULL;
The namespace of the PHP is the same as my controllers.
I have also tried this in order to create an instance of the globalSettingsRepository:
$objectManager = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance('TYPO3\\CMS\\Extbase\\Object\\ObjectManager');
Which does not work either because /TYPO3/CMS/... was not found.
Does anyone have a solution? Is there even a way to access a repository from /Resources?
Thanks alot.
There are some things that should be fixed in your extension.
First of all, you should not use TYPO3 as vendor for your extension. This is only for the core and official extensions.
Second, you must stick to conventions.
\TYPO3\Institutsvideoverwaltung\Domain\Repository\GlobalSettingsRepository
This means that you must have a class called \TYPO3\Institutsvideoverwaltung\Domain\Repository\GlobalSettingsRepository at the following path: /typo3conf/ext/institutsvideoverwaltung/Classes/Domain/Repository/GlobalSettingsRepository.php.
It seems that you don't and instead put it in Resources/PHP.
If you want to use a class from Resources/PHP, you need to either include it manually using require_once() or you need to make sure that your class is autoloaded properly. The requirements for autoloading changed from version 6 to 7, so you need to state which version you're using. Nevertheless it doesn't make sense to break convention and then have a lot of effort of there is a simple way.

NetBeans autocompletion with Doctrine models?

I know it's possible to get IDE autocompletion from the *Table classes in Doctrine by doing things like this:
SomethingTable::getInstance()-><autocomplete>;
But the most important part is missing. I want autocomplete on the model classes themselves, not just the Table classes. It appears that Doctrine is not properly declaring the PHPdoc #return object types in the find and other standard model methods.
For example what I want to be able to do is this:
$something = SomethingTable::getInstance()->find($id);
$something-><autocomplete>
and have that pop up the methods and properties of the Something class.
I should mention too that I don't specifically care about using the SomethingTable::getInstance() syntax at all. ANY decent syntax that's standard Symfony is acceptable. Most of the time I'm fetching objects (or Doctrine_Collections) via custom queries like this:
$somethings = Doctrine_Query::create()
->from('Something s')
->leftJoin('s.SomethingElse s2')
->where(...);
By the way, in case it's not clear, I'm asking if there's any automatic solution to this with ANY of the various Doctrine find, fetch or query syntaxes. I'm NOT asking how to manually edit all the PHPdoc headers to cause the behavior I want.
I'm using NetBeans 6.9.1 and Symfony 1.4.12 with Doctrine, but not everyone working on the same code uses NetBeans.
The problem is that autogenerated *Table classes have the wrong phpdoc #return in the getInstance() method:
/**
* Returns an instance of this class.
*
* #return object MyModelTable
*/
public static function getInstance()
{
return Doctrine_Core::getTable('MyModel');
}
You just need to manually fix the #return line deleting the word "object":
* #return MyModelTable
And magically IDE autocompletion just works, giving you all the instance and static methods:
MyModelable::getInstance()->... //(you'll have autocompletion here)
I know, its a pain to have to manually fix this but at least it only have to be done once for each model *Table file.
In netbeans its quite easy:
$foo = ModelNameTable::getInstance()->find(1); /* #var $foo ModelName */
/* #var $foo ModelName */ tells netbeans to handle the variable $foo as a ModelName class.
just fix the generated model files by adding
/**
* #return ModelNameTable
*/
in the comment of the getInstance() method. This will provide autocomplete for the model file.
Regarding the find method, you can edit the comment of the class like this :
/**
* #method ModelName find()
*/
I think it might be possible for you to do this automatically by creating you own skeleton files.
Or not : Symfony Doctrine skeleton files
You could use sed to achieve this, or perhaps build your own task using the reflection api.

Is it good practice to make static find methods in Doctrine models

Sometimes I have complicated find procedures and I'm feeling dirty to repeat this code in my Controller.
Now I am thinking, it is possible to do something like this:
class User extends BaseUser
{
private static function getTable()
{
return Doctrine_Core::getTable('User');
}
public static function findAll()
{
return getTable()->findAll();
}
public function currentEnrolments() {
$query = Doctrine_Query::create()
->from('Enrolment e')
->where('e.user_id = ?', $this->id)
->addWhere('e.finish_date IS NULL');
return $query->execute();
}
}
Is this a good practice? Or should I only put non static members like the query I have shown?
Generally, if it saves you time, there nothing to lose and every minute you can save to gain.
Functions like getTable and findAll are probably not saving you a lot, but custom queries for finding stuff more specific to your application will definitely be worth it.
I have got pretty much the same approach.
I wouldn't bother with your static proxies of getTable() and findAll().
That doesn't really add any value to your code
I, personnaly, never call findAll() on any model object as you will generally need
to cross-check against a foreign key
paginate / sort
...
regarding your currentEnrolments() function, this is worth doing as you have a bit of logic on this ->addWhere('e.finish_date IS NULL'), thus explaining you can't use the "magic" Doctrine relation ->Enrolment. Maybe this is something Doctrine 2 is resolving, need to check this out ...
Regards