Symfony5控制器调用自定义Service报错及查询异常求助
问题1:控制器中无法获取自定义服务
问题描述
在Symfony 5中尝试通过容器获取自定义服务book.manager时,触发以下错误:
Service "book.manager" not found: even though it exists in the app's container, the container inside "App\Controller\HomeController" is a smaller service locator that only knows about the "doctrine", "form.factory", "http_kernel", "parameter_bag", "request_stack", "router", "security.authorization_checker", "security.csrf.token_manager", "security.token_storage", "serializer", "session" and "twig" services. Try using dependency injection instead.
相关代码及配置:
BookManager.php
<?php namespace App\Service; use App\Entity\BookContent; use Doctrine\ORM\EntityManagerInterface; class BookManager { protected $entityManager; public function __construct(EntityManagerInterface $entityManager) { $this->entityManager = $entityManager; } public function getBookTitle(string $page){ return $this->entityManager->getRepository(BookContent::class) ->findOneBy(["page"=>$page])->getTitle(); }
service.yml 配置
.... services: book.manager: class: App\Service\BookManager arguments: ['@doctrine.orm.entity_manager'] public: true
控制器调用代码
$pageName = $this->container->get('request_stack')->getMasterRequest()->get('_route'); $bookTitle = $this->container->get('book.manager')->getBookTitle($pageName);
解决方法
Symfony 5默认通过服务定位器限制控制器可直接调用的服务,禁止直接从容器获取未授权的服务。正确方案是使用依赖注入注入自定义服务:
方案1:构造函数注入
修改控制器代码,在构造函数中注入BookManager:
<?php namespace App\Controller; use App\Service\BookManager; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Component\HttpFoundation\Response; class HomeController extends AbstractController { private $bookManager; // 构造函数注入BookManager public function __construct(BookManager $bookManager) { $this->bookManager = $bookManager; } public function index() { $pageName = $this->get('request_stack')->getMasterRequest()->get('_route'); $bookTitle = $this->bookManager->getBookTitle($pageName); // 后续业务逻辑 return new Response($bookTitle); } }
方案2:属性注入(Symfony 5.4+ 支持)
若使用Symfony 5.4及以上版本,可直接用方法参数注入简化代码:
<?php namespace App\Controller; use App\Service\BookManager; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Component\HttpFoundation\Response; class HomeController extends AbstractController { public function index(BookManager $bookManager) { $pageName = $this->get('request_stack')->getMasterRequest()->get('_route'); $bookTitle = $bookManager->getBookTitle($pageName); return new Response($bookTitle); } }
注意:Symfony会自动注册App\Service命名空间下的服务,无需手动修改service.yml,除非需要自定义服务ID或参数。
问题2:
findOneBy(["page"=>$page]) 返回null触发错误 问题描述
改用依赖注入后,findOneById(["id"=>$id])可正常查询,但使用findOneBy(["page"=>$page])时出现以下错误:
Impossible to access an attribute ("title") on a null variable.
解决方法
该错误说明findOneBy(["page"=>$page])未匹配到任何BookContent记录,返回了null,直接调用->getTitle()就会触发报错。需按以下步骤排查修复:
1. 验证查询参数准确性
先确认$page变量的值是否与数据库中BookContent表的page字段值完全匹配(注意大小写、空格、特殊字符等),可添加调试代码:
public function getBookTitle(string $page){ // 打印page值确认是否正确 var_dump($page); $bookContent = $this->entityManager->getRepository(BookContent::class)->findOneBy(["page"=>$page]); // 打印查询结果 var_dump($bookContent); if (!$bookContent) { // 无匹配记录时的处理逻辑,比如返回默认值或抛出异常 return '默认标题'; // 或抛异常:throw new \Exception("未找到page为{$page}的书籍内容"); } return $bookContent->getTitle(); }
2. 检查实体字段映射
确认BookContent实体中page字段的映射是否与数据库一致:
// BookContent.php use Doctrine\ORM\Mapping as ORM; /** * @ORM\Entity(repositoryClass="App\Repository\BookContentRepository") */ class BookContent { // ...其他字段 /** * @ORM\Column(type="string", length=255) // 确认类型、长度与数据库匹配 */ private $page; // ...对应的getter、setter方法 }
3. 调试SQL查询语句
在.env文件中开启Doctrine调试日志,查看实际执行的SQL:
APP_ENV=dev ###> doctrine/doctrine-bundle ### DOCTRINE_DEBUG=true ###< doctrine/doctrine-bundle ###
将日志中的SQL语句拿到数据库中执行,确认是否存在匹配记录。
4. 强制处理空值场景
无论查询结果是否为空,都应在代码中做判断,避免直接调用方法:
public function getBookTitle(string $page): string { $bookContent = $this->entityManager->getRepository(BookContent::class)->findOneBy(["page" => $page]); return $bookContent ? $bookContent->getTitle() : '默认标题'; }
内容的提问来源于stack exchange,提问作者Nll
相关产品推荐
相关产品推荐

