I’m a beginner and I’m trying to follow a tutorial to create a blog under Symfony 7, unfortunately I find myself stuck with an error when I want to display the page of an article using his address (slug) I get:
Controller "AppControllerArticleController::show" requires the "$article" argument that could not be resolved. Cannot autowire argument $article of "AppControllerArticleController::show()": it needs an instance of "AppEntityArticle" but this type has been excluded in "config/services.yaml".
It was when I injected my Article entity into the show function of my ArticleController that the problem occurred.
<?php
namespace AppController;
use AppEntityArticle;
use SymfonyBundleFrameworkBundleControllerAbstractController;
use SymfonyComponentHttpFoundationResponse;
use SymfonyComponentRoutingAttributeRoute;
class ArticleController extends AbstractController
{
#[Route('/article/{slug}', name: 'article_show')]
public function show(Article $article): Response
{
return $this->render('article/show.html.twig', [
'article' => $article,
]);
}
}
When I use the link from the home page, the route displayed is correct (with the slug).
Any idea how I could fix this? (it must be something really simple but I don’t understand)
I tried to check my code, especially the entity:
<?php
namespace AppEntity;
use AppModelTimestampedInterface;
use AppRepositoryArticleRepository;
use DoctrineCommonCollectionsArrayCollection;
use DoctrineCommonCollectionsCollection;
use DoctrineDBALTypesTypes;
use DoctrineORMMapping as ORM;
#[ORMEntity(repositoryClass: ArticleRepository::class)]
class Article implements TimestampedInterface
{
#[ORMId]
#[ORMGeneratedValue]
#[ORMColumn]
private ?int $id = null;
#[ORMColumn(length: 255)]
private ?string $title = null;
#[ORMColumn(length: 255)]
private ?string $slug = null;
#[ORMColumn(type: Types::TEXT, nullable: true)]
private ?string $content = null;
#[ORMColumn(length: 100, nullable: true)]
private ?string $featuredText = null;
#[ORMColumn(type: Types::DATETIME_MUTABLE)]
private ?DateTimeInterface $createdAt = null;
#[ORMColumn(type: Types::DATETIME_MUTABLE, nullable: true)]
private ?DateTimeInterface $updatedAt = null;
/**
* @var Collection<int, Category>
*/
#[ORMManyToMany(targetEntity: Category::class, mappedBy: 'articles')]
private Collection $categories;
/**
* @var Collection<int, Comment>
*/
#[ORMOneToMany(targetEntity: Comment::class, mappedBy: 'article', orphanRemoval: true)]
private Collection $comments;
#[ORMManyToOne]
private ?Media $featuredImage = null;
public function __construct()
{
$this->categories = new ArrayCollection();
$this->comments = new ArrayCollection();
}
public function getId(): ?int
{
return $this->id;
}
public function getTitle(): ?string
{
return $this->title;
}
public function setTitle(string $title): static
{
$this->title = $title;
return $this;
}
public function getSlug(): ?string
{
return $this->slug;
}
public function setSlug(string $slug): static
{
$this->slug = $slug;
return $this;
}
public function getContent(): ?string
{
return $this->content;
}
public function setContent(?string $content): static
{
$this->content = $content;
return $this;
}
public function getFeaturedText(): ?string
{
return $this->featuredText;
}
public function setFeaturedText(?string $featuredText): static
{
$this->featuredText = $featuredText;
return $this;
}
public function getCreatedAt(): ?DateTimeInterface
{
return $this->createdAt;
}
public function setCreatedAt(DateTimeInterface $createdAt): static
{
$this->createdAt = $createdAt;
return $this;
}
public function getUpdatedAt(): ?DateTimeInterface
{
return $this->updatedAt;
}
public function setUpdatedAt(?DateTimeInterface $updatedAt): static
{
$this->updatedAt = $updatedAt;
return $this;
}
/**
* @return Collection<int, Category>
*/
public function getCategories(): Collection
{
return $this->categories;
}
public function addCategory(Category $category): static
{
if (!$this->categories->contains($category)) {
$this->categories->add($category);
$category->addArticle($this);
}
return $this;
}
public function removeCategory(Category $category): static
{
if ($this->categories->removeElement($category)) {
$category->removeArticle($this);
}
return $this;
}
/**
* @return Collection<int, Comment>
*/
public function getComments(): Collection
{
return $this->comments;
}
public function addComment(Comment $comment): static
{
if (!$this->comments->contains($comment)) {
$this->comments->add($comment);
$comment->setArticle($this);
}
return $this;
}
public function removeComment(Comment $comment): static
{
if ($this->comments->removeElement($comment)) {
// set the owning side to null (unless already changed)
if ($comment->getArticle() === $this) {
$comment->setArticle(null);
}
}
return $this;
}
public function getFeaturedImage(): ?Media
{
return $this->featuredImage;
}
public function setFeaturedImage(?Media $featuredImage): static
{
$this->featuredImage = $featuredImage;
return $this;
}
}
You understood it, the goal is therefore to display the article page :
{% extends 'base.html.twig' %}
{% block title %}{{ article.title }}{% endblock %}
{% block body %}
<div class="container">
<h1>{{ article.title }}</h1>
<hr>
{{ article.content|raw }}
</div>
{% endblock %}
Many thanks,
EDIT1: Here is the code of the home page where the link to the article page is generated. But whatever the slug indicated in the url (whether it exists or not in the database), the error message is the same.
{% extends 'base.html.twig' %}
{% block title %}Accueil{% endblock %}
{% block body %}
<main class="container">
<div class="row">
<div class="col-md-8">
<h3 class="pb-4 mb-4 fst-italic border-bottom">Articles récents</h3>
<div id="articles-list">
{% include 'article/list.html.twig' with { articles } %}
</div>
</div>
<div class="col-md-4">
<div class="position-sticky" style="top: 2rem;">
{% include 'widget/about.html.twig' %}
{% include 'widget/categories.html.twig' %}
</div>
</div>
</div>
</main>
{% endblock %}
The template list.html.twig :
{% for article in articles %}
{% include 'article/item.html.twig' with { article } %}
{% endfor %}
item.html.twig :
{% set article_show = path('article_show', { 'slug': article.slug }) %}
<article class="mb-5">
<div class="row">
<div class="col-md-5">
{% if article.featuredImage %}
<a href="{{ article_show }}">
<img src="/uploads/{{ article.featuredImage.filename }}" alt="{{ article.featuredImage.altText }}" loading="lazy" width="350" height="205">
</a>
{% endif %}
</div>
<div class="col-md-7">
<h2>
<a class="text-decoration-none" href="{{ article_show }}">{{ article.title }}</a>
</h2>
<p>
{{ article.createdAt|date('d M Y') }}
</p>
{{ article.featuredText ?: article.content|striptags|slice(0, 130) ~ '...' }}
</div>
</div>
</article>
EDIT2, I only have one article in the database and it does have a slug. Normally the slug cannot be null, but if I manage to get past this step, I will add a redirection in case the article cannot be found:
class ArticleController extends AbstractController
{
#[Route('/article/{slug}', name: 'article_show')]
public function show(?Article $article): Response
{
if (!$article) {
return $this->redirectToRoute('app_home');
}
return $this->render('article/show.html.twig', [
'article' => $article,
]);
}
}
For the moment if I apply this code, the article is not found and we return to the home page (this seems normal considering the error I had before that).
EDIT3, Here is the HomeController with the findAll():
<?php
namespace AppController;
use AppRepositoryArticleRepository;
use SymfonyBundleFrameworkBundleControllerAbstractController;
use SymfonyComponentHttpFoundationResponse;
use SymfonyComponentRoutingAttributeRoute;
class HomeController extends AbstractController
{
#[Route('/', name: 'app_home')]
public function index(ArticleRepository $articleRepo): Response
{
return $this->render('home/index.html.twig', [
'articles' => $articleRepo->findAll()
]);
}
}
And ArticleRepository :
<?php
namespace AppRepository;
use AppEntityArticle;
use DoctrineBundleDoctrineBundleRepositoryServiceEntityRepository;
use DoctrinePersistenceManagerRegistry;
class ArticleRepository extends ServiceEntityRepository
{
public function __construct(ManagerRegistry $registry)
{
parent::__construct($registry, Article::class);
}
}
2
Answers
You can use the MapEntity attribute to solve your problem this way :
The mapEntity attribute will allow Symfony to find the entity with the slug you have in your route parameter.
The error say
So I guess there is some
in this file, so if you removed that line …