0

I have a question for my Symfony project.

I have this code which shows the number of rows in a given database table:

// BudgetRepository
public function countBudgets()
{
  $qb = $this->createQueryBuilder('budget');
  return $qb
    ->select('count(budget.id)')
    ->getQuery()
    ->getSingleScalarResult();
}
// BudgetController
public function all(EntityManagerInterface $entityManager)
{
  $repository = $entityManager->getRepository(Budget::class);
  $count = $repository->countBudgets();
  return $this->render("budget/budget.html.twig", ['numberOfBudgets' => $count]);
}

It works, but it only works inside budget/budget.html.twig by usung {{ numberOfBudgets }}.

How can I make it work on every page (specifically I want it to be placed in my file called _sidebar.html.twig? Right now if I place {{ numberOfBudgets }} onto _sidebar.html.twig I get this error message "Variable "numberOfBudgets" does not exist".

How should I rewrite the code?

yivi
  • 42,438
  • 18
  • 116
  • 138
  • What's the relationship between `budget.html.twig` and `_sidebar.html.twig`? When and how are you rendering this sidebar? I would imagine the sidebar is not rendered independently, right? – yivi Mar 17 '22 at 10:29
  • @yivi It's rendered at the beginning of the base.html.twig page (right after the opening body-tag) by using `{{ include('_sidebar.html.twig') }}` – FreePalestine Mar 17 '22 at 10:36
  • Something is wrong then. If the template was included just as you say, the variable **would be visible as well**. From the docs: "Included templates have access to the variables of the active context.". (https://twig.symfony.com/doc/3.x/functions/include.html) – yivi Mar 17 '22 at 10:38
  • 1
    You'll need to include minimal twig examples that reliably reproduce the issue. – yivi Mar 17 '22 at 10:39
  • @yivi I think you have misunderstood - or more likely that I haven't been totally clear. It does work on both the base file and the sidebar file - but if I place `{{ numberOfBudgets }}` on the sidebar and open a different URL then it the error "Variable "numberOfBudgets" occours. Probably because the variable is set to only page/URL only. Should I then go for global twig variables? – FreePalestine Mar 17 '22 at 10:52
  • You have several options here. [How to inject global variables into all templates?](https://stackoverflow.com/a/55935970/1426539) – yivi Mar 17 '22 at 10:53

2 Answers2

0

You should use global twig variable. Move Your code to service:

class BudgetService
{
    public function all(EntityManagerInterface $entityManager)
    {
        $repository = $entityManager->getRepository(Budget::class);
        return $repository->countBudgets();
    }
}

Then register global variable in twig configuration (config/packages/twig.yaml):

twig:
  globals:
    budget: '@App\Services\BudgetService'

Then You can use it in any template like:

Total: {{ budget.all }}
Bogdan Kuštan
  • 5,427
  • 1
  • 21
  • 30
  • Not the downvoter, but I'm afraid this is not really relevant here. The question is not about "global twig variables", simply about a visibility problem across included templates (something that would not require creating a global variable at all) – yivi Mar 17 '22 at 10:42
  • And if the question **was** about creating global twig variables, there are tons of dupes to choose from :) – yivi Mar 17 '22 at 10:43
  • Sometimes people don't know that global twig variables exists :) – Bogdan Kuštan Mar 17 '22 at 10:47
  • @BogdanKuštan Hello Bogdan! Thanks for the example. That works - almost - I get the following error, and how do I solve it? `Too few arguments to function App\Service\BudgetService::all(), 0 passed in \budget\vendor\twig\twig\src\Extension\CoreExtension.php on line 1599 and exactly 1 expected` - I do understand the error, but how do I fix it? How can I leave out the argument in all()? – FreePalestine Mar 18 '22 at 09:12
  • @FreePalestine I would use constructor injection and inject EntityManager (or even better BudgetRepository directly) in __construct(EntityManagerInterface $entityManager) then assign it to some private variable ($this->entityManager = $entityManager). – Bogdan Kuštan Mar 18 '22 at 09:19
  • @BogdanKuštan Thank you - I really appreciate the help. I fixed it by injecting BudgetRepository directly :-))) – FreePalestine Mar 18 '22 at 09:42
-1

I would go for a session variable, take a look at Symfony Session to access your count variable but make sure to update this var in session if any change occurs.

public function index(EntityManagerInterface $em) 
{
    $count = $em->getRepository(Budget::class)->countBudgets();

    $session = $this->requestStack->getSession();
    $session->set('budgetCount', $count);
}

To access the session var in your twig template, take a look at App global variable.

<p>Total budgets: {{ app;session.budgetCount }}</p>
Skunka
  • 525
  • 2
  • 6
  • 22
  • Not the downvoter, but I'm afraid this is wrong. The question is not about having a value persist across requests (which the session would help with), but simply about variable visibility across included templates. – yivi Mar 17 '22 at 10:41
  • Well, I though that persist his var in session was enabling him to access it from any twig template, which make it visible for any template no ? (correct me if I'm wrong, it's only for understanding !) – Skunka Mar 17 '22 at 13:58