Controller class not seeing method from repository class - symfony

I have spent the last few hours trying to find an answer however not gaining at all. I feel that it will end up being something simple that I did not have knowledge of. This section of code is of course incorrect but I wanted to show the idea of what I was trying to do here. I currently have a base repository class that has the findAllQueryBuilder method within it that will allow for reduced code. Right now I have about 10 repository classes that all need to use findAllQueryBuilder. This function is within the basecontroller I have built. The main issue is that this controllor does not see findAllQueryBuilder because as you can see this takes in the parameters to determine which data location is needed. I've done this once already in another location in my code with an interface however that was with a class I will put that example here also.
public function listAction(Request $request, RepositoryTypeInterface $repositoryName, $table, $sql, $route)
{
$filter = $request->query->get('filter');
$repository = "Bundle:$repositoryName";
$qb = $this->getDoctrine()
->getRepository($repository, 'tenant')
->findAllQueryBuilder($filter, $table, $sql);
As you can see in the following I set the type as the interface to make sure it knew that it was going to be that then.
public function newAction(Request $request, EntityTypeInterface $controllerType, formType, $repository, $routeName)
{
And then instantiated it within the childclass controllor
public function newAction(Request $request, EntityTypeInterface $controllerType = null, $formType = ContactType::class, $repository = 'Contact', $routeName = 'api_contacts_show')
{
$controllerType = new Contact();
return parent::newAction($request, $controllerType, $formType, $repository, $routeName);
}
So The first example above has me attempting the same thing however I am not sure how to apply this to this situation. as "Bundle:$repository" is a string and the parameter used is a string and it's not an entity so creating an instance doesn't make sense when all I need is its functionality. I just need some way to have access to this functionality. any ideas would work but I'm feeling like I'm missing something simple.
Here is the exact error I get,
Method 'findAllQueryBuilder' not found in \Doctrine\Common\Persistence\ObjectRepository
Referenced method is not found in subject class.
I'm sure there is a way to apply this concept to fix the lack of 'seeing' the function however as of right now I'm not completely sure.
Thank you anyone in advance.
EDIT:
I'm using a basecontrollor that is setting this up for the other controllers ie:cantactscontrollor class which uses the ContactEntity class mapped to the contactrepository class which is a child of a baserepository class which is where findAllQueryBuilder is located, I'm not sure how to map that.

public function listAction(Request $request, $repositoryName, $table, $sql, $route)
{
$filter = $request->query->get('filter');
$repository = "TenantBundle:$repositoryName";
/** #var RepositoryTypeInterface $qb */
$qb = $this->getDoctrine()
->getRepository($repository, 'tenant');
$queryResults = $qb->findAllQueryBuilder($filter, $table, $sql);
Sorry for the late response on this but here is the answer I was able to find. As I thought it was a simple thing but essentially the Docblock labeled $qb as the said interface above making sure it knew that any class that implements it will be accepted. Now knowing what type it will be, the error message is no longer there. Notice also how I split it up.

Related

symfony / doctrine : entity wont delete

I have this code in Symfony 3:
(...)
$annonceActive = $em->getRepository('AppBundle:AnnonceActive')
->find($SomeKnownId);
$profilPresta = $em->getRepository('AppBundle:Profil')
->find($SomeKnownId);
$annonceEnCours = new AnnonceEnCours();
$this->get('app_annonce_transportateur')
->transporterAnnonce($annonceActive, $annonceEnCours);
$annonceEnCours->setPresta($profilPresta);
$em->remove($annonceActive);
$em->persist($annonceEnCours);
$em->flush();
dump($annonceActive);
//annonceActive stills exists !!
Now I have the service used :
class TransportateurElementAnnonce
{
protected $em;
public function __construct(EntityManager $entityManager){
$this->em = $entityManager;
}
protected function copierInfosAnnonceVersAnnonce(&$annonceSource, &$annonceTarget)
{
$annonceTarget->setAuteur($annonceSource->getAuteur());
$annonceTarget->setPresta($annonceSource->getPresta());
$annonceTarget->setCompetence($annonceSource->getCompetence());
$annonceTarget->setGroupeCompetence($annonceSource->getGroupeCompetence());
$annonceTarget->setTitre($annonceSource->getTitre());
$annonceTarget->setSlug($annonceSource->getSlug());
$annonceTarget->setDescription($annonceSource->getDescription());
$annonceTarget->setPrix($annonceSource->getPrix());
$annonceTarget->setServiceADistance($annonceSource->getServiceADistance());
$annonceTarget->setDateCreation($annonceSource->getDateCreation());
}
public function transporterAnnonce(&$annonceSource, &$annonceTarget)
{
$this->copierInfosAnnonceVersAnnonce($annonceSource, $annonceTarget);
$this->em->persist($annonceSource);
$this->em->persist($annonceTarget);
$this->em->remove($annonceSource);
$this->em->flush();
}
}
How can I use $em->remove($annonceActive) in the controller, and still have an object !
I really tried everything, I dont get it.
Thanks in advance !
You can use clone to "copy" an object, that way you can use the copied object after you've changed the original using the entity manager (or whatever you want to do with it).
$originalObject = new SomeClass();
$clonedObject = clone $originalObject;
// Change the original object here, for example use it with the entity manager..
$originalObject->setWhatever('bla');
$this->em->persist($originalObject);
$this->em->flush();
// At this point $clonedObject is still unchanged.
More information on cloning objects: http://php.net/manual/en/language.oop5.cloning.php
Hope this helps..
the solution was given by #jacek : I remove all interaction with the entity manager in the service, and used it only in the controller.
My service looks like before, except I dont use entity manager !
Thanks guys for the precious help.

Symfony2: Using Doctrine outside controller

I'm a bit of noob when it comes to OOP PHP, so please forgive me if I make this sound more complicated then it is.
Basically I am trying to clean up my controller as it's starting to get too cluttered.
I have my entities set up and I have also created a repository to add methods for some db queries to a sqlite database.
But now I also have to manipulate this data before outputting it, I've created a separate connector class that fetches additional info (from an XML web source) for each item being queried and then this gets added to the doctrine query data before being outputted.
I could manipulate this data in the repository but the data I am adding obviously doesn't originate from my entity. So I have therefore created a separate model class to add this data.
Please tell me if I'm on the right track.
In my entity repository I will have a custom method like this:
public function queryTop10All()
{
$query = $this->getEntityManager($this->em)
->createQueryBuilder('u')
->select('u.ratingkey, u.origTitle, u.origTitleEp, u.episode, u.season, u.year, u.xml, count(u.title) as playCount')
->from($this->class, 'u')
->groupBy('u.title')
->orderBy('playCount', 'desc')
->addOrderBy('u.ratingkey', 'desc')
->setMaxResults(10)
->getQuery();
return $query->getResult();
}
Now I created a new class in \Model\ChartsDataModel.php and I am injecting doctrine into it using a service and calling the custom method, getting the results and then adding the additional data from the web connector to it, like so:
namespace PWW\DataFactoryBundle\Model;
use Doctrine\ORM\EntityManager;
use PWW\DataFactoryBundle\Connector\XMLExtractor;
use PWW\DataFactoryBundle\Connector\WebConnector;
use PWW\ContentBundle\Entity\Settings;
class ChartsDataModel {
private $settings;
private $repository;
private $em;
public function __construct(EntityManager $em)
{
$this->settings = new Settings();
$this->repository = $this->settings->getGroupingCharts() ? 'PWWDataFactoryBundle:Grouped' : 'PWWDataFactoryBundle:Processed';
$this->em = $em;
}
public function getChartsTop10All()
{
$xmlExtractor = new XMLExtractor();
$webConnector = new WebConnector();
$results = $this->em->getRepository($this->repository)->queryTop10All();
$xml = $xmlExtractor->unXmlArray($results);
$outputArray = array();
foreach($xml as $item) {
$outputArray[] = array(
"ratingKey" => $item['ratingkey'],
"origTitle" => $item['origTitle'],
"origTitleEp" => $item['origTitleEp'],
"playCount" => $item['playCount'],
"episode" => $item['episode'],
"season" => $item['season'],
"year" => $item['year'],
"type" => $item['media']['type'],
"parent" => $webConnector->getMetaData($webConnector->getMetaDataParentKey($item['ratingkey'])),
"metadata" => $webConnector->getMetaData($item['ratingkey'])
);
}
return $outputArray;
}
}
The xmlExtractor class is used to pull out certain xml fields stored in a database field as a raw xml dump.
My config.yml:
services:
pww.datafactorybundle.model.charts_data_model:
class: PWW\DataFactoryBundle\Model\ChartsDataModel
arguments: [ #doctrine.orm.entity_manager ]
Then in my controller, I just instantiate a new ChartsDataModel and call the method like so:
namespace PWW\ContentBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
...
use PWW\DataFactoryBundle\Model\ChartsDataModel;
public function chartsAction()
{
$charts = new ChartsDataModel($this->getDoctrine()->getManager());
$top10Array = $charts->getChartsTop10All();
return $this->render('PWWContentBundle:Default:charts.html.twig', array('page' => 'charts', 'top10' => $top10Array));
}
I just want to know if I am doing this correctly and is there a better way of doing this (or right way)?
I'm also very new to Symfony and still getting my head around it. I just don't want to get into bad habits so I'm trying to do things right from the start.
I hope I explained this well enough :)
TIA
Just detected two things that are in the top of my head.
1 If you define the service like:
services:
pww.datafactorybundle.model.charts_data_model:
class: PWW\DataFactoryBundle\Model\ChartsDataModel
arguments: [ #doctrine.orm.entity_manager ]
Then you can inject it in the controller like described here, so you keep the service arguments out of the Controller:
public function chartsAction()
{
$myservice = $this->get('pww.datafactorybundle.model.charts_data_model');
$top10Array = $myservice->getChartsTop10All();
}
Secondly, I would not put this standard queries in the Model, I think is better to keep the models clean with their setters, getters and put this custom queries elsewhere like in a service that will handle all related Chart queries and you can instance from anywhere else.

Symfony2 FOSRestBundle: Which class to include for codes like HTTP_NO_CONTENT

I wanna throw an HTTP_NO_CONTENT, but symfony tells me that ClassNotFoundException: Attempted to load class "Codes" from namespace "FOS\Rest\Util". Do you need to "use" it from another namespace?
I actually did use FOS\RestBundle\Util\Codes; in my class.
My call looks like this
public function deleteAction($id)
{
$em = $this->getDoctrine()->getManager();
$player = $em->getRepository('xxx')->find($id);
$em->remove($player);
$em->flush();
return $this->view(null, new HTTP_NO_CONTENT);
}
Why is it not possible to find that class?
new HTTP_NO_CONTENT doesn't make sens here! You've to use FOS\RestBundle\Util\Codes class,
use FOS\RestBundle\Util\Codes;
and point to the right status code as follow,
Codes::HTTP_NO_CONTENT // As HTTP_NO_CONTENT is defined as a constant

$this object not working properly when used in services in Symfony2

I've working for a while with Symfony and I started to use controllers as services. The problem is that I'm not sure if I get how the Dependency Injection works. If I print $this inside an action it works perfectly.
/**
* #Route("/testing/this")
*/
public function thisAction(Request $request)
{
var_dump($this);
return new Response();
}
Response:
object(Linkedip\WizardBundle\Controller\PaymentsController)[153]
protected 'object' => null
protected 'container' =>
object(appDevDebugProjectContainer)[198]
protected 'parameterBag' =>
object(Symfony\Component\DependencyInjection\ParameterBag\FrozenParameterBag)[48]
protected 'parameters' =>
array
...
But then, I decided to make my controller a service to be used in other controllers (I want to have actions methods and service methods in one controller).
parameters:
linkedip.controller.payments.class: Linkedip\WizardBundle\Controller\PaymentsController
services:
payments.controller:
class: %linkedip.controller.payments.class%
So, I add a new method that I'll plan to use in other controllers but when I try to call $this inside the new method look what I get.
/**
* #Route("/testing/this")
*/
public function thisAction(Request $request)
{
$paymentsController = $this->get('payments.controller');
$paymentsController->service();
return new Response();
}
/**
* [SERVICE]
*/
public function service()
{
var_dump($this);
return null;
}
Response:
object(Linkedip\WizardBundle\Controller\PaymentsController)[937]
protected 'object' => null
protected 'container' => null
To solve this issue I created a setter to inject $this object directly to the controller.
/**
* [DEPENDENCY INJECTION]
*/
protected $object;
public function setObject($object) { $this->object = $object; }
And then, When I try to call one of those services I need to add an extra line setting $this.
$paymentsController = $this->get('payments.controller');
$paymentsController->setObject($this);
And in the service method, I call the object.
$em = $this->object->getDoctrine()->getManager();
This code works for me but I feel is a dirty trick. Am I doing something wrong?
[..]But then, I decided to make my controller a service to be used in other controllers (I want to have actions methods and service methods in one controller).
I don't agree with this architecture choice. You should make your own controller to let the other ones herits from it. Then, if you still need a service, you can create one.
I agree with goto, you should not mix responsibilities within one class. Also, this is mainly the cause for your problem. To answer your question:
By defining your controller as a service, you are not using the default instantiation logic for a controller, so the container will not be injected automatically. If you want this to happen, you should manually inject the container (or better: the specific services you need) from within your dependency injection config. But, again, if you plan on still using the controller in the 'regular' way, by defining routes for example, things will get REALLY messy, so I would suggest, if you are already playing with the DIC, just create a separate service and call that from within your other controller. Hope this helps.

Class not found when trying to index documents using Solr with Symfony2

I am very new to Solr and I am probably missing something simple however, having followed Xavier Briand's presentation I have set up Symfony2, Solarium and Nelmio\SolariumBundle.
"nelmio/solarium-bundle": "2.0.*#dev",
"solarium/solarium": "3.0.*"
Having implemented a toSolrDocument method for my doctrine php object.
public function toSolrDocument(\Solarium_Document_ReadWrite $doc)
{
$doc->id = $this->getId();
$doc->description = $this->getTitle();
$doc->path = "path";
return $doc;
}
I am faced with the following error.
Catchable Fatal Error: Argument 1 passed to ::toSolrDocument() must be an instance of Solarium_Document_ReadWrite, instance of Solarium\QueryType\Update\Query\Document given, called in Controller.php
The controller calling this toSolrDocument method has the following function
public function indexItems(){
$client = $this->get('solarium.client');
// get an update query instance
$update = $client->createUpdate();
// create documents
$documents = array();
$em = $this->getDoctrine()->getManager();
$repo = $em->getRepository('<Bundle>:<Object>');
$items = $repo->findAll();
foreach ($items as $item) {
$documents[] = $item->toSolrDocument($update->createDocument());
}
// add the documents and a commit command to the update query
$update->addDocuments($documents);
$update->addCommit();
// this executes the query and returns the result
$result = $client->update($update);
}
Most of this method again comes directly from Xavier's presentation and it is clear to see that the method $update->createDocument() does not return the correct type. In fact it returns an instance of the my php object. Does anyone know where I am going wrong here? Another thing that might be of help is that even when I try to pass a Solarium Document directly I get an exception.
foreach ($items as $item) {
$rw_item = new \Solarium_Document_ReadWrite();
$documents[] = $item->toSolrDocument($rw_item);
}
The exception is
FatalErrorException: Error: Class 'Solarium_Document_ReadWrite' not found in
I can't seem to find this class in any of the bundles and I am wondering if my setup might be causing the issues. Any help would be very much appreciated.
One additional point to note is that when I am running the solr jar I see the query requests come in from my symfony2 page it is only this indexing action that I can not work out so the config may be alright and I am miss understanding the use of the bundle.
You just need to use the correct class for the argument.
use Solarium\QueryType\Select\Result\AbstractDocument;
...
public function toSolrDocument(AbstractDocument $doc)
{
You could also not type hint it:
public function toSolrDocument($doc)
{

Resources