1

I'm trying to setup a search function as a service. My code is below and am getting the following error when submitting the search word:

FatalErrorException: Error: Call to undefined method Acme\ProjectBundle\Services\Search::getDoctrine() in /var/www/html/Project/src/Acme/ProjectBundle/Services/Search.php line 24

Do I need to inject doctrine somehow?

config.yml

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

IndexAction Controller

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

Search service

class Search
{
private $request;

public function __construct(RequestStack $requestStack)
{
    $this->request = $requestStack->getCurrentRequest();
}

public function search()
{
    $results = null;
    $query = $this->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();
    }
//        exit(\Doctrine\Common\Util\Debug::dump($em));
    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={{ app.request.query.get('q') }}></label>
    <input type="submit" value="Search">
</form>
<br>
{% endblock %}

{% for result in query %}

    <div class="container">
    <div class="row">
        <div class="col-sm-8 blog-main">
            <div class="blog-post">

                <h2 class="blog-post-title">{{ result.title }}</h2>
                <p class="blog-post-meta"><time datetime="{{ result.created|date('c') }}">{{ result.created|date('l, F j, Y') }}</time> by <a href="#">{{ result.author }}</a></p>

                <p>{{ result.blog|truncate(350, true) }}</p><br>

                <div class="tags">
                    <p><strong>Tags: </strong><span class="highlight">{{ result.tags }}</span></p>
                </div>

            </div><!-- /.blog-post -->
        </div>
    </div>
</div>
{% endfor %}
webdev
  • 741
  • 5
  • 16

2 Answers2

1

Yes, you need to inject doctrine 'manually'. Your service definition should look like:

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

And your constructor should look like:

use Doctrine\Bundle\DoctrineBundle\Registry;
public function __construct(RequestStack $requestStack, Registry $doctrine)
{
    $this->request = $requestStack->getCurrentRequest();
    $this->doctrine = $doctrine;
}

and then you can use it in your search method:

public function search()
{
    (...)
    $em = $this->doctrine->getManager()
}

NOTE: $this->getDoctrine() method you're trying to use is a method of Symfony\Bundle\FrameworkBundle\Controller class, and you're probably get used to using it from your controllers, but your own service you need to inject doctrine as a dependency

Tomasz Madeyski
  • 10,742
  • 3
  • 50
  • 62
  • Thank you for the in-depth explanation. That took care of the error but am now running into (Impossible to access an attribute ("title") on a string variable ("practice") in AcmeProjectBundle:Default:search.html.twig at line 31) -- "practice" is a search word for one of the titles I'm looking for. Does my query need to be changed in the search class? – webdev Apr 02 '14 at 06:03
  • It's hard to tell without seeing more code. You don't need `:` sign in your setParameter call, maybe this is the case. – Tomasz Madeyski Apr 02 '14 at 06:09
  • This is continuation question from my original that's still unresolved: http://stackoverflow.com/questions/22796723/symfony2-how-to-implement-this-search-function-as-a-service – webdev Apr 02 '14 at 06:12
  • By : do you mean to not use ->setParameter('`:`search', "%${query}%") ? – webdev Apr 02 '14 at 06:13
  • Yes, you can do ->setParameter('search', "%${query}%") but this is rather blind shot – Tomasz Madeyski Apr 02 '14 at 06:14
  • And for `->where('b.title LIKE :search')` do I keep the `:`? – webdev Apr 02 '14 at 06:15
  • yes, you do (some additional characters to match minimal comment lenght) – Tomasz Madeyski Apr 02 '14 at 06:17
  • I tried that (removed the : on parameter) and I changed the code in the twig file to use query instead of results for the for loop (for result in query), the 'impossible' error is now gone but the query turns up nothing. Seems my query code is broke when trying to make it into a re-usable service. – webdev Apr 02 '14 at 06:18
1

You need to make the container inject an EntityManager into your service.

services:
    search:
    class: Acme\ProjectBundle\Services\Search
    arguments: ["@request_stack","@doctrine.orm.entity_manager"]
    scope: request
Nisam
  • 2,275
  • 21
  • 32