I use TYPO3 6.1.
I actually try to test a method with phpunit which uses a injected repository.
$mock = $this->getMockedRepository(
'\\MyExt\\Domain\\Repository\\MyRepository',
array(
'findByUid' => array('count' => 0, 'return' => array()),
)
);
$this->tokenHelperObj->injectMyRepository($mock);
The function getMockedRepository is just a helper that calls the getMock-function from phpunit. In other context this function works. In my helper-class i just use dependency injection like
/**
* myRepository
*
* #var \MyExt\Domain\Repository\MyRepository
* #inject
*/
protected $myRepository;
When i call the test, i get
Call to undefined method Class::injectActivityRepository()
I dont want to write all inject-methods for the different repositories i use. Is there any other way to mock the injected repositories?
Since TYPO3 6.1 the class \TYPO3\CMS\Core\Tests\UnitTestCase has been extended with the new method called inject(). This method can be used to inject dependiencies, so you don't have to create inject-methods.
Usage:
$this->inject($target, $name, $dependency)
Below follows an example test:
/**
* #test
*/
public function serviceReturnsFalseIfNoRecordsFoundTest() {
$mockQuery = $this->getMock('TYPO3\CMS\Extbase\Persistence\QueryInterface');
$mockRepository = $this->getMock('\TYPO3\MyExtension\Domain\Repository\TestRepository');
$mockRepository->expects($this->once())->method('findAll')->will($this->returnValue($mockQuery));
$this->inject($this->fixture, 'testRepository', $mockRepository);
$this->assertTrue($this->fixture->doSomething());
}
Related
I'm trying to start a client using Search_api_solr v4.1, Solarium v6.0 and symfony/event-dispatcher v3.4.47 but I keep getting a TypeError.
TypeError: Argument 2 passed to Solarium\Core\Client\Client::__construct()
must be an instance of Psr\EventDispatcher\EventDispatcherInterface,
instance of Symfony\Component\EventDispatcher\EventDispatcher given
I'm not quite sure why it's expecting an instance of Psr\EventDispatcher\EventDispatcherInterface when all the documentation on solarium says to use Symfony\Component\EventDispatcher\EventDispatcher.
My adapter and event Dispatcher is as below
use Solarium\Client;
use Solarium\Core\Client\Adapter\Curl;
use Symfony\Component\EventDispatcher\EventDispatcher;
function get_search_query() {
$adapter = new Curl();
$eventDispatcher = new EventDispatcher();
$config = ['endpoint' => ['localhost' => [
'host' => $id,
'port' => $port,
'path' => '/',
'collection' => '$core',],],];
$search = new Client($adapter, $eventDispatcher, $config);
$query = $search->createSelect();
}
Has anyone else ran into this issue or knows a fix for this?
When you are creating the solarium client at new Client() the second parameter expects you to give a class implementing Psr\EventDispatcher\EventDispatcherInterface. However, in your use statement the EventDispatcher you are creating is Symfony\Component\EventDispatcher\EventDispatcher.
Change the use statement to the PSR event dispatcher and you should be fine.
When you dig into the Symfony source you can view this :
if (interface_exists(PsrEventDispatcherInterface::class)) {
/**
* Allows providing hooks on domain-specific lifecycles by dispatching events.
*/
interface EventDispatcherInterface extends PsrEventDispatcherInterface
{
/**
* Dispatches an event to all registered listeners.
*
* For BC with Symfony 4, the $eventName argument is not declared explicitly on the
* signature of the method. Implementations that are not bound by this BC constraint
* MUST declare it explicitly, as allowed by PHP.
*
* #param object $event The event to pass to the event handlers/listeners
* #param string|null $eventName The name of the event to dispatch. If not supplied,
* the class of $event should be used instead.
*
* #return object The passed $event MUST be returned
*/
public function dispatch($event/*, string $eventName = null*/);
}
} else {
/**
* Allows providing hooks on domain-specific lifecycles by dispatching events.
*/
interface EventDispatcherInterface
{
/**
* Dispatches an event to all registered listeners.
*
* For BC with Symfony 4, the $eventName argument is not declared explicitly on the
* signature of the method. Implementations that are not bound by this BC constraint
* MUST declare it explicitly, as allowed by PHP.
*
* #param object $event The event to pass to the event handlers/listeners
* #param string|null $eventName The name of the event to dispatch. If not supplied,
* the class of $event should be used instead.
*
* #return object The passed $event MUST be returned
*/
public function dispatch($event/*, string $eventName = null*/);
}
}
So your issue is that interface_exists(PsrEventDispatcherInterface::class) returns false. THis interface comes from this package https://packagist.org/packages/psr/event-dispatcher so I would try a composer require psr/event-dispatcher to fix it.
EDIT : Your version of symfony's event dispatcher is outdated. Update to 5.3 to fix the issue.
Is it possible to set up a search for multiple entities, using the Florian Semm Solr Bundle in Symfony? I'm completely lost, have looked in the documentation of Solarium itself, but couldn't figure out how to set up a search for our Symfony project.
Here's what I did so far:
Solarium and the SolrBundle are both successfully installed.
I indexed 3 entities (for now) with the Solr annotations like that:
/**
* #Solr\Document(repository="UserBundle\Entity\User")
* #Solr\Document(index="*")
*/
class User {
/**
* #Solr\Id
*/
protected $id;
/**
* #Solr\Field(type="string")
*/
protected $firstName;
/**
* #Solr\Field(type="string")
*/
protected $lastName;
}
I set up a controller where I call the solr.client but that's basically how far I got. I can show you my code but it's throwing error messages, because I'm basically just trying around:
class SearchController extends Controller {
/**
* #Route("/search-result/", name="searchBundle")
*/
public function searchAction(Request $request) {
$client = $this->get('solr.client');
$query = $client->createSelect();
$query->setQuery($request->query->all());
// this executes the query and returns the result
$resultset = $client->execute($query);
return $this->render('SearchBundle::search.html.twig', array(
'resultset' => $resultset
));
}
}
How do I get the controller/the bundle to search within all the three bundles/indexed properties?
How do I structure the output?
Couldn't find any tutorials/example codes/guidelines for that specific bundle unfortunately.
What you probably want to do inside your controller is get a repository for the search;
$resultset = $this->get('solr.client')->getRepository('UserBundle:User')->findAll();
return $this->render('SearchBundle::search.html.twig', array(
'resultset' => $resultset
));
Source: https://github.com/floriansemm/SolrBundle#query-a-field-of-a-document
I'm new to Symfony2. I have to learn it for my new job (it starts this monday). Before that, I used a lot CodeIgniter... so this change a bit.
After reading tons of documentations, tuts, best practices ... create my Own intranet for testing (customers has websites, websites has accesses, accesses has website, website has category, accesses has accesscategory) I still have some questions.
First Question :
When you have a website with frontend and backend you have all the time some repetitives actions like :
- create new entity
- read entity
- update entity
- delete entity
...
In CI, I create a BaseController and a BaseModel and with some extends, I was OK.
This practice is still OK for Symfony 2 or do Symfony have another way to handle that ?
Like AppBundle\Controller\BaseController extended by a AppBundle\Controller\AdminController (and FrontController) extended by AppBundle\Controller\MyEntityController ?
Because Actually, each time, in each controller I have the same code. When I edit an entity (for example), it's the same process : load the entity by id, throw exception if no entity, create and hydrate the form, handleRequest the post and valid the form, reidrect or display the view... but... I always cut/paste the same code... aweful T__T
So I'm searching for the best way to handle that
** Second Question : **
What is the best and elegent way to work with the DoctrineManager ?
Do I have to call it, each time in my actions ? $em = $this->get... or, can I create something like MyEntityManager which call the EntityManager and the repository of my entity ?
Actually, this is what I do :
I create an abstract AppBundle\Manager\BaseManager with loadAndFlush
<?php
namespace AppBundle\Manager;
abstract class BaseManager
{
protected function persistAndFlush($entity)
{
$this->em->persist($entity);
$this->em->flush();
}
}
Then, for each Entity, I create his own manager :
<?php
namespace AppBundle\Manager;
use Doctrine\ORM\EntityManager;
use AppBundle\Manager\BaseManager;
use AppBundle\Entity\Customer;
class CustomerManager extends BaseManager
{
/**
* #var EntityManager
*/
protected $em;
/**
* #param EntityManager $em
*/
public function __construct(EntityManager $em)
{
$this->em = $em;
}
/**
* #param $customerId
* #return null|object
*/
public function loadCustomer($customerId)
{
return $this->getRepository()
->findOneBy(array('id' => $customerId));
}
/**
* #param Customer $customer
*/
public function saveCustomer(Customer $customer)
{
$this->persistAndFlush($customer);
}
/**
* #return \Doctrine\ORM\EntityRepository
*/
public function getRepository()
{
return $this->em->getRepository('AppBundle:Customer');
}
}
Then, I define this manager as a service :
parameters:
app.customer_manager.class: AppBundle\Manager\CustomerManager
services:
app.customer_manager:
class: %app.customer_manager.class%
arguments: [#doctrine.orm.entity_manager]
And Then I use the service in my Controller :
/**
* #Route("/edit/{customerId}", name="customer_edit")
* #Security("has_role('ROLE_ADMIN')")
*/
public function editAction($customerId, Request $request)
{
if (!$customer = $this->get('app.customer_manager')->loadCustomer($customerId)) {
throw new NotFoundHttpException($this->get('translator')->trans('This customer does not exist.'));
}
$form = $this->get('form.factory')->create(new CustomerType(), $customer);
if($form->handleRequest($request)->isValid()) {
$this->get('app.customer_manager')->saveCustomer($customer);
$request->getSession()->getFlashBag()->add('notice', 'Client bien enregistré.');
return $this->redirect(
$this->generateUrl(
'customer_show', array(
'customerId' => $customer->getId()
)
)
);
}
return $this->render('default/customer/add.html.twig', array(
'form' => $form->createView(),
'customer' => $customer
));
}
Is it a good practice, is it too complicated ? Is there any better other way to process in symfony ?
For first question Symfony2 provides CRUD Generator, take a look at this.
For second one you should use Repository Pattern provided by framework, for more information about this checkout following links:
http://msdn.microsoft.com/en-us/library/ff649690.aspx
http://symfony.com/doc/current/book/doctrine.html#custom-repository-classes
I have been using Silex for my latest project and I was trying to follow along with the "How to Dynamically Modify Forms Using Form Events" in the Symfony cookbook. I got to the part that uses the entity field type and realized it is not available in Silex.
It looks like the symfony/doctrine-bridge can be added to my composer.json which contains the "EntityType". Has anyone successfully got entity type to work in Silex or run into this issue and found a workaround?
I was thinking something like this might work:
$builder
->add('myentity', new EntityType($objectManager, $queryBuilder, 'Path\To\Entity'), array(
))
;
I also found this answer which looks like it might do the trick by extending the form.factory but haven't attempted yet.
I use this Gist to add EntityType field in Silex.
But the trick is register the DoctrineOrmExtension form extension by extending form.extensions like FormServiceProvider doc says.
DoctrineOrmExtension expects an ManagerRegistry interface in its constructor, that can be implemented extending Doctrine\Common\Persistence\AbstractManagerRegistry as the follow:
<?php
namespace MyNamespace\Form\Extensions\Doctrine\Bridge;
use Doctrine\Common\Persistence\AbstractManagerRegistry;
use Silex\Application;
/**
* References Doctrine connections and entity/document managers.
*
* #author Саша Стаменковић <umpirsky#gmail.com>
*/
class ManagerRegistry extends AbstractManagerRegistry
{
/**
* #var Application
*/
protected $container;
protected function getService($name)
{
return $this->container[$name];
}
protected function resetService($name)
{
unset($this->container[$name]);
}
public function getAliasNamespace($alias)
{
throw new \BadMethodCallException('Namespace aliases not supported.');
}
public function setContainer(Application $container)
{
$this->container = $container['orm.ems'];
}
}
So, to register the form extension i use:
// Doctrine Brigde for form extension
$app['form.extensions'] = $app->share($app->extend('form.extensions', function ($extensions) use ($app) {
$manager = new MyNamespace\Form\Extensions\Doctrine\Bridge\ManagerRegistry(
null, array(), array('default'), null, null, '\Doctrine\ORM\Proxy\Proxy'
);
$manager->setContainer($app);
$extensions[] = new Symfony\Bridge\Doctrine\Form\DoctrineOrmExtension($manager);
return $extensions;
}));
I am using the FOSRestBundle to create a REST application but since REST features is only a part, I am also using some of Symfony2 built-in automation tools to generate my CRUD code. Everything works fine but I am unable to correctly map the route and I will appreciate some insight and example on how to do this manually. I have read the manual route definition in the FOS manual stating to use the given annotations but how do I do this since the CRUD code created by Symfony2 uses a different annotation?
Here is an example:
class UserController extends Controller
{
/**
* Lists all User entities.
*
* #Route("/", name="user")
* #Method("GET")
* #Template()
*/
public function indexAction()
{
$em = $this->getDoctrine()->getManager();
$entities = $em->getRepository('CompanyWebServicesBundle:User')->findAll();
return array(
'entities' => $entities,
);
}
FOSRest manual gives the annotation for GET as
use FOS\RestBundle\Controller\Annotations\Get;
/**
* GET Route annotation.
* #Get("/likes/{type}/{typeId}")
*/
When I use the route as /index, it gives me an error and my route definition in config.yml is:
index:
type: rest
resource: Company\WebservicesBundle\Controller\UserController
How can I fix this problem?
If I were you, I would create separate bundles for your REST controllers and your generic CRUD controllers. This will make things easier to maintain (in my opinion). For example, create a AcmeMainBundle and a AcmeRestBundle, and then create a separate class to actually perform the actions that you will call from both bundles. Something like this:
// src/Acme/MainBundle/Crud/User.php (create this folder structure)
class User{
private $em;
public function __construct($em){
$this->em = $em;
}
public function getUser($id){
return $this->em->getRepository('AcmeMainBundle:User')->find($id);
}
}
Then:
// src/Acme/MainBundle/Controller/UserController.php
use Symfony\Component\HttpFoundation\Request;
use Acme\MainBundle\Crud\User;
class UserController extends Controller {
public function getAction($request){
$em = $this->getDoctrine()->getManager();
$getUser = new User($em);
$user = $getUser ->getUser($request->query->get('user_id'));
// return response
}
}
And then:
// src/Acme/RestBundle/Controller/UserController.php
use FOS\RestBundle\Controller\Annotations as Rest;
use FOS\RestBundle\Routing\ClassResourceInterface;
use Symfony\Component\HttpFoundation\Request;
class UserController extends Controller implements ClassResourceInterface {
/**
* #Rest\View()
*/
public function getAction($id){
$em = $this->getDoctrine()->getManager();
$getUser = new User($em);
$user = $getUser ->getUser($id);
// return using the default format defined in config.yml
return array(
"success"=>'true',
"user" => $user
);
} // get_user [GET] /users/{id}
}
Please note that using the ClassResourceInterface means your method names will be used to generate the routes. see FOSRestBundle Docs for more info on that.
You can do something similar to this for all your CRUD, that way you keep your routes separate and maintainable, but still have a single code base to update.