Call ElasticaBundle Finder and Index in a Service - symfony

On my project I use FOSElastica to filter many entities, then I use the same portion of code on many pages:
$query = ('' !== $request->get('q') && null !== $request->get('q')) ? $request->get('q') : null;
$teamId = ('' !== $request->get('team') && null !== $request->get('team')) ? $request->get('team') : $this->getUser()->getFavoriteTeam()->getId();
$page = (0 < (int) $request->get('p')) ? $request->get('p') : 1;
$repositoryManager = $this->get('fos_elastica.manager.orm');
$repository = $repositoryManager->getRepository('AppBundle:BiologicalOriginCategory');
$elasticQuery = $repository->searchByNameQuery($query, $page, $teamId, $this->getUser());
$categoryList = $this->get('fos_elastica.finder.app.biologicalorigincategory')->find($elasticQuery);
$nbResults = $this->get('fos_elastica.index.app.biologicalorigincategory')->count($elasticQuery);
$nbPages = ceil($nbResults / BiologicalOriginCategory::NUM_ITEMS);
In the previous code the only things that changes: class used to filter, sometimes by team, sometimes by project, sometimes no filtering.
I would want avoid replication code by doing an IndexFilter util, then, I just call the IndexFilter service, give him: the class I want filter, the queryString, and the class(es) used to filter it.
It works well for the 6 first lines, because I can call it directly in my service.
But I don't know how I can dynamically call ElasticaBundle Finder and Index:
$categoryList = $this->get('fos_elastica.finder.app.biologicalorigincategory')->find($elasticQuery);
$nbResults = $this->get('fos_elastica.index.app.biologicalorigincategory')->count($elasticQuery);
I'm forced to inject it in the Service, but there is more than 10 entities, I can't inject 20 different other services each time and juste use 2 of them...
Are there a way to retrieve Finder and Index with the class name ? (AppBundle\Entity\BiologicalOriginCategory) ? I do it for retrieve the repository $repository = $repositoryManager->getRepository($class); and it works.
Thanks a lot for your help.
EDIT:
I've maybe a solution to bypass the prolem, but not resolve it by using the fos_elastica.finder.app and fos_elastica.index.app.
Then when I do a query, Elasticsearch do in on the whole index, and in my RepositoryMethod, I add a \Elastica\Query\Type() to filter results by Type.
I think it's less efficient than do a request whithout QueryType bu on the specific Type. No ?

Related

Symfony 2 Variable Entity Naming

I feel like this shouldn't be to hard, but try as I might, I keep getting errors.
What I'm wanting to do, is to have a single "add" function that will handle the basic functionality of adding records to any / all tables. Basically, the post data will contain the table name, as well as the fields / values to be inserted. The controller itself, confirms the user has access to do these things, and then verifies the fields are valid, before creating a new instance of the entity, that's where things go haywire:
$entityName = 'Products';
$row = new $entityName(); //doesn't work
$row new Products(); //works
I haven't found a way or any examples of creating a new entity using the Entity Manager, or else that might work, because i've created functions using EM to do queries, updates, and deletes, but I just can't get this to work with the add functions.
1. Your problem is almost certainly namespacing (see below). Try this instead:
$entityName = 'My\Bundle\Entity\Products';
$row = new $entityName();
Should work. ;)
2. If you want to create new instances using an EntityManager, try this:
$entityName = 'My\Bundle\Entity\Products';
$row = $em->getClassMetadata($entityName)->newInstance();
...assuming $em is your EntityManager. :-)
3. To "prove" that your problem is namespacing, try this in a plain .php file that you run from the command line:
namespace Foo;
class Test {}
$class1 = 'Foo\Test';
$class2 = 'Test';
$x = new Test(); // Will work
$y = new $class1(); // Will work
$z = new $class2(); // Will trigger "Class 'Test' not found" fatal error
Two things:
Try with "Products" instead of 'Products'
I suppose that your entity Products has a namespace, it is required (even if you declared an use statement). So try with "My\Bundle\Entity\Products".

Best practice for storing simple variables like 'total rows' in Symfony2

In my symfony2 application I need to display some totals at the top of all pages, ie "Already 200,154,555 users registered".
I don't want to run the query to come up with that count on every page load. The solution I've come up with is to create a "variable" entity that would have two columns, name and value. Then I would set up a console command that runs on cron which would update these variable entities (eg "totalPeople") with a query that counted all the rows of people, etc.
This feels a little heavy handed... Is there a better solution to this problem?
You could set global parameters and add a service to rewrite them. Then call the service from your Command.
Or directly set up a service to read/write a file (as a json array for example).
Or set up a option table with a row storing the data. It's not going to be a resource intensive query that way.
Here is what I'm using to store RSS feeds (after I parsed them)
public function checkCache($data=array(), $path = '')
{
foreach ($data as $service => $feed)
{
$service = strtolower($service);
$service = str_replace(' ', '-', $service);
$path = $path.'web/bundles/citation/cache/rss/' . $service . '.cache';
if ((!file_exists($path) || time() - filemtime($path) > 900) && $cache = fopen($path, 'w'))
{
$rss_contents = $this->getFeed($feed); //fetch feed content & returns array
fwrite($cache, serialize($rss_contents));
fclose($cache);
return $rss_contents;
}
else
{
$cache = fopen($path, 'r');
return unserialize(file_get_contents($path));
fclose($cache);
}
}
}
You can implement that on your backend for example so every time an admin logs it'll check for cache and refresh only if it's too old. Although I'm quite fond of the 4AM cron job solution too.
You could use the pagination feature of doctrine (if you use doctrine). That will leverage the "limit" part of your queries (even with joins) and will give you a total count of rows (via a count query).

Define custom method and access it from twig

I have two entities in 1:n relations: Race and Day - a race may have more days. This is the simple model:
Race (id)
Day (id, race_id, is_active, is_deleted)
I want to access the superior one - Race - within a Symfony2 project via Doctrine and display results in a Twig template. For the direct Race attributes it is easy.
However, it becomes trickier, when I want to use a custom defined method (sort of flag, let's call it hasActiveDays()) in Race that reflects if the race had any active and not deleted days. Simple Doctrine relation would not be enough, so I need to use a query like this:
SELECT d FROM mtboLibBundle:Day d WHERE d.isActive = 1 AND d.isDeleted = 0 AND d.raceId = :id
My question is basicly where/how to implement this query and how to invoke it in a twig template? Anything I tried resulted various errors so far, so I'd be grateful if someone could help.
I.e. this was a try:
class RaceRepository extends EntityRepository {
public function hasActiveDays() {
$em = $this->getEntityManager();
$query = $em->createQuery('SELECT f FROM mtboLibBundle:Day d
WHERE d.isActive = 1
AND d.isDeleted = 0
AND d.raceId = :id')
->setParameter('id', $this->id)
;
$days = $query->getResult();
return (count($days) == 0) ? false : true;
}
}
Method does not exist - when called from the template:
{{ race.hasActiveDays }}
I don't think you'll be able to call a function in a repository the way you are trying to do. One thing I've done is put a function on the entity class and you can call that from your template.
In your Race class:
public function hasActiveDays(){
// here, perhaps pull all of the days for this race - maybe from a doctrine relation
// loop through, filter, etc.
// return whatever is appropriate
}
... then, in your template, you'll be able to call that function the way you are trying to above.

is it possible to set a field in drupal to some value by using nodeapi

So I have this field named field_movie_cast_count this is a field of a content named movie so what I want is that whenever the movie is updated (like I add another cast member) the field_movie_cast_count field would be updated too. I have successfully done it using this code:
function count_cast_nodeapi(&$node, $op) {
$id = $node->nid;
if($op == 'update' && $node->type == 'movie') {
$count=count($node->field_movie_cast);
$q = db_query("update content_type_movie set field_movie_cast_count_value = '$count' WHERE nid = '$id'");
}
}
Now, my boss told me that I should not use query. So, how do I achieve this by not using a database query?
is it not possible to just set field_movie_cast_count[]['value']=$count? i tried this code it doesnt work. lol
OR SHOULD I REPHRASE THE QUESTION is there any other way of displaying the count cast? aside from my way? cause maybe i did not understand my boss right.
hook_nodeapi() has a presave operation which is invoked just before the node (and field data) is committed to the database. The definition of the operation is:
The node passed validation and is about to be saved. Modules may use this to make changes to the node before it is saved to the database.
You can use it to update a field value, without resorting to hitting the database manually (which will be overwritten anyway) like so:
function MYMODULE_nodeapi(&$node, $op) {
if ($op == 'presave' && $node->type == 'movie') {
$node->field_movie_cast_count[0]['value'] = count($node->field_movie_cast);
}
}

doctrine querybuilder limit and offset

i'm a symfony beginner and i want to make a blog with the framework. i use repository to get home articles with this method :
public function getHomeArticles($offset = null, $limit = null)
{
$qb = $this->createQueryBuilder('a')
->leftJoin('a.comments', 'c')
->addSelect('c')
->addOrderBy('a.created', 'DESC');
if (false === is_null($offset))
$qb->setFirstResult($offset);
if (false === is_null($limit))
$qb->setMaxResults($limit);
return $qb->getQuery()
->getResult();
}
so in my database i have 10 articles. In my BlogController i use :
$blog = $em->getRepository('TestBlogBundle:Article')
->getHomeArticles(3,4);
With this i want 4 articles. But in return i also have one article.
What is the problem?
This is a know issue where setFirstResult() and setMaxResults() need to be use with care if your query contains a fetch-joined collection.
As stated about First and Max Result Items:
If your query contains a fetch-joined collection specifying the result
limit methods are not working as you would expect. Set Max Results
restricts the number of database result rows, however in the case of
fetch-joined collections one root entity might appear in many rows,
effectively hydrating less than the specified number of results.
Instead, you can:
Lazy load
use the Paginator (as stated by #Marco here)
Use Doctrine\Common\Collections\Collection::slice()

Resources