1

I would like to use this code as a service so I don't have repeat this in every controller. How would I go about using this as a service so that it functions as below?

I've read some documentation and set it up as a service per below but am unsure how this is supposed to work to pass in the variables into the twig template.

Am currently accessing it as $search = $this->get("search")->search(); but am getting an error as I pass in 'search' => $search into the twig.

(ContextErrorException: Catchable Fatal Error: Argument 1 passed to Acme\ProjectBundle\Services\Search::search() must be an instance of Acme\ProjectBundle\Services\Request, none given, called in /var/www/html/Project/src/Acme/ProjectBundle/Controller/PageController.php on line 30 and defined in /var/www/html/Project/src/Acme/ProjectBundle/Services/Search.php line 8)

What is the proper way to do this and call it in the controller???

Original Index controller without the service

public function indexAction(Request $request)
{

    // Search code
    $results = null;
    $query = $request->query->get('q');

    if (!empty($query)) {
        $em = $this->getDoctrine()->getManager();

        $results = $em->createQueryBuilder()
            ->from('AcmeProjectBundle:Blog', 'b')
            ->select('b')
            ->where('b.title LIKE :search')
            ->setParameter(':search', "%${query}%")
            ->getQuery()
            ->getResult();
    }

    return $this->render('AcmeProjectBundle:Default:index.html.twig', array(
        'query'        => $query,
        'results'      => $results,
    ));
}

Service Search class

class Search
{
   public function search(Request $request)
   {
      $results = null;
      $query = $request->query->get('q');

      if (!empty($query)) {
          $em = $this->getDoctrine()->getManager();
          $results = $em->createQueryBuilder()
            ->from('AcmeProjectBundle:Blog', 'b')
            ->select('b')
            ->where('b.title LIKE :search')
            ->setParameter(':search', "%${query}%")
            ->getQuery()
            ->getResult();
      }

      return array(
          'query'   => $query,
          'results' => $results,
       );
   }
}

index.html.twig

{% block search %}
<form action="{{ path('acme_project_search') }}" method="GET">
    <label><input type="search" name="q" value={{ query }}></label>
    <input type="submit" value="Search">
</form>
<br>
{% endblock %}

config.yml

services:
   search:
      class: Acme\ProjectBundle\Services\Search
webdev
  • 741
  • 5
  • 16

2 Answers2

0

If you are trying to inject the request service, you would be better to inject the request_stack service instead and access the current Request by calling the getCurrentRequest()

class Search
{
    protected $request;

    public function __construct(RequestStack $requestStack)
    {
        $this->request = $requestStack->getCurrentRequest();
        //Do any kinds of initializing you need
    }

    public function mySearch()
    {
       $results = null;
       $query = $this->request->query->get('q');
       //Do your search base on $query
       //I suggest to send the container instead of RequestStack because you want to do search by using EntityManger, too
       //Return the results
    }
}

and change your service.yml as below and set the scope to "request"

services:
   search:
      class:     Acme\ProjectBundle\Services\Search
      arguments: ["@request_stack"]
      scope: "request"

You also have another option to send the container as a parameter to your service and in your service use container->getRequset()

Javad
  • 4,339
  • 3
  • 21
  • 36
  • Ok, how would I call this within the IndexAction controller using this method and what do I pass into the twig template? – webdev Apr 01 '14 at 22:00
  • You should be able to call it by using get: `$myService = $this->get('search');` I would also suggest to create some function for search and call that one, not in the constructor; check my updated answer – Javad Apr 02 '14 at 01:07
  • I'm getting the following: (ContextErrorException: Catchable Fatal Error: Object of class Acme\ProjectBundle\Services\Search could not be converted to string in /var/www/html/Project/app/cache/dev/twig/a9/d5/ec64445ba94847aea163fec49e2ba1e15015f9cfd67e257d23f8e5b3595e.php line 39) – webdev Apr 02 '14 at 01:45
  • 1) I added the changes you recommended copied the __construct as per the example and and left my original search code as is under it. 2) Assigned $query = $this->get('search'); and passed this to the twig template in IndexAction controller and came up with the following error above. – webdev Apr 02 '14 at 01:47
  • Why did you pass `$query` to the twig file? `$query` is just a handler for the service you can call the search function like `$query->mySearch()` then it will return the results – Javad Apr 02 '14 at 01:59
  • However in that case your service needs more changes because you cannot use `$this->getDoctrine()->getManager()` in your service function while you did not send `container` as a service parameter, too – Javad Apr 02 '14 at 02:00
  • What does it need to be changed to, and how do you send a container? – webdev Apr 02 '14 at 02:03
  • Per the twig posted above, I am using a variable {{ query }} in the form. So based on what you're saying I should pass $query->mySearch() to twig? – webdev Apr 02 '14 at 02:05
  • First in twig file that you just want to show the searched string in the input value you should change it to `value="{{ app.request.query.get('q') }}"` – Javad Apr 02 '14 at 02:11
  • Ok that fixed the error. When putting in a search it seems I am missing the 'results' variable that's in the search function array in the search class. Passed in the results as $results = null in the index controller then passed into twig, fixed the error but the search does not work. Nothing comes up when entering a search title. – webdev Apr 02 '14 at 02:15
  • How do you call the search function to get results? – Javad Apr 02 '14 at 02:20
  • In the IndexAction I am using ($query = $this->get('search'); and $results = null; Then I am passing these two into twig, return $this->render('AcmeProjectBundle:Default:index.html.twig', array( 'query' => $query, 'results' => $results)); – webdev Apr 02 '14 at 02:22
  • Am using the search function as listed above in the search class. – webdev Apr 02 '14 at 02:54
  • In my answer I named it as `mySearch` so your code in indexAction can be something like: `$query = $this->get('search'); $result = $query->mySearch();` then pass the `$result` to your twig file – Javad Apr 02 '14 at 03:00
  • Ok, now apparently getDoctrine is undefined now? (FatalErrorException: Error: Call to undefined method Acme\ProjectBundle\Services\Search::getDoctrine() in /var/www/html/Project/src/Acme/ProjectBundle/Services/Search.php line 24) The search function is exactly as it's listed above in my original question. – webdev Apr 02 '14 at 03:26
  • Do I need to inject doctrine in the config.yml? – webdev Apr 02 '14 at 03:54
  • No you don't need to inject Doctrine if you pass `container` as service argument. In fact if you pass the container as argument you won't need to pass any other params even you don't need to pass the Request in your service because they all exists in container. Check this answer [http://stackoverflow.com/questions/17126277/how-to-give-container-as-argument-to-services] – Javad Apr 02 '14 at 13:51
0

You need to inject Request into your service:

search:
    class: Acme\ProjectBundle\Services\Search
    scope: request
    arguments: [@request]

then in your Search class:

private $request;

public function __construct(Request $request)
{
    $this->request = $request;
}

after that whenever you need to access Request inside your service just use $this->request. And remove Request $request parameter injection in your search function.

UPDATE:

Your indexAction would become like this:

public function indexAction(Request $request)
{
    return $this->render('AcmeProjectBundle:Default:index.html.twig',
        $this->get('search')->search()
    );
}
dmnptr
  • 4,258
  • 1
  • 20
  • 19
  • How would I call this in the IndexAction controller with this setup and what do I pass into the twig template? – webdev Apr 01 '14 at 22:00
  • Ok, let me know if I'm following correctly: 1) I've added the private $request; and public function __construct(Request $request) to the class Search. 2) And below this I still have my search function. 3) Then in the index controller I have assigned $query = $this->get('search')->search() and passed query => $query onto my twig file. I get the following error: (ContextErrorException: Catchable Fatal Error: Argument 1 passed to Acme\ProjectBundle\Services\Search::__construct() – webdev Apr 01 '14 at 22:49
  • ContextErrorException: Catchable Fatal Error: Argument 1 passed to Acme\ProjectBundle\Services\Search::__construct() must be an instance of Acme\ProjectBundle\Services\Request, instance of Symfony\Component\HttpFoundation\Request given, called in /var/www/html/Project/app/cache/dev/appDevDebugProjectContainer.php on line 1777 and defined in /var/www/html/Project/src/Acme/ProjectBundle/Services/Search.php line 12 – webdev Apr 01 '14 at 22:50
  • It looks like you have incorrect use statement for `Request` in your `Search` class. Add this one - `use Symfony\Component\HttpFoundation\Request;` – dmnptr Apr 02 '14 at 16:57