Symfony4如何实现全局可调用的数据库配置服务(非构造注入)
当然可行!我来给你一步步实现这个需求
要在Symfony4里打造一个像$this->getDoctrine()那样随用随取的全局配置服务,而且不用构造注入、配置数据来自数据库表,完全可以做到。下面是具体的实现步骤:
1. 先搞定数据库层:配置实体与仓库
首先你需要一个存储配置的数据库表,对应的实体和Repository:
// src/Entity/Config.php namespace App\Entity; use Doctrine\ORM\Mapping as ORM; /** * @ORM\Entity(repositoryClass="App\Repository\ConfigRepository") */ class Config { /** * @ORM\Id() * @ORM\GeneratedValue() * @ORM\Column(type="integer") */ private $id; /** * @ORM\Column(type="string", length=255, unique=true) */ private $key; /** * @ORM\Column(type="text", nullable=true) */ private $value; // 生成getter和setter方法 public function getId(): ?int { return $this->id; } public function getKey(): ?string { return $this->key; } public function setKey(string $key): self { $this->key = $key; return $this; } public function getValue(): ?string { return $this->value; } public function setValue(?string $value): self { $this->value = $value; return $this; } }
// src/Repository/ConfigRepository.php namespace App\Repository; use App\Entity\Config; use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository; use Doctrine\Common\Persistence\ManagerRegistry; class ConfigRepository extends ServiceEntityRepository { public function __construct(ManagerRegistry $registry) { parent::__construct($registry, Config::class); } // 根据key获取配置值的方法 public function getValueByKey(string $key): ?string { $config = $this->findOneBy(['key' => $key]); return $config ? $config->getValue() : null; } }
2. 核心:创建全局配置服务
接下来写一个ConfigService,负责从数据库读取配置并处理缓存(避免每次请求都查库):
// src/Service/ConfigService.php namespace App\Service; use App\Repository\ConfigRepository; use Symfony\Contracts\Cache\CacheInterface; use Symfony\Contracts\Cache\ItemInterface; class ConfigService { private $configRepo; private $cache; public function __construct(ConfigRepository $configRepo, CacheInterface $cache) { $this->configRepo = $configRepo; $this->cache = $cache; } // 获取配置值的方法 public function get(string $key): ?string { // 用缓存优化,缓存有效期可以根据自己需求调整 return $this->cache->get('config_'.$key, function(ItemInterface $item) use ($key) { $item->expiresAfter(3600); // 缓存1小时 return $this->configRepo->getValueByKey($key); }); } }
然后在config/services.yaml里把这个服务注册为公共服务(因为我们要通过容器直接获取,Symfony4默认服务是私有):
services: # ... 其他服务配置 App\Service\ConfigService: arguments: $configRepo: '@App\Repository\ConfigRepository' $cache: '@cache.app' public: true
3. 控制器里像用getDoctrine一样调用
为了让所有控制器不用构造注入就能快速获取这个服务,我们可以写一个Trait:
// src/Controller/ConfigTrait.php namespace App\Controller; use App\Service\ConfigService; trait ConfigTrait { /** * 获取全局配置服务 */ protected function getConfig(): ConfigService { return $this->container->get(ConfigService::class); } }
之后,任何控制器只要引入这个Trait,就能像调用getDoctrine()一样用getConfig()了:
// src/Controller/SomeController.php namespace App\Controller; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; class SomeController extends AbstractController { use ConfigTrait; public function index() { // 直接获取配置值 $siteName = $this->getConfig()->get('site_name'); return $this->render('some/index.html.twig', [ 'site_name' => $siteName ]); } }
4. 监听器里也能轻松获取
监听器里要获取这个服务,只需要注入Symfony的容器(或者直接获取容器)。比如写一个请求监听器:
// src/EventListener/ConfigListener.php namespace App\EventListener; use Symfony\Component\DependencyInjection\ContainerInterface; use Symfony\Component\HttpKernel\Event\RequestEvent; use App\Service\ConfigService; class ConfigListener { private $container; public function __construct(ContainerInterface $container) { $this->container = $container; } public function onKernelRequest(RequestEvent $event) { // 获取配置服务 $configService = $this->container->get(ConfigService::class); $maintenanceMode = $configService->get('maintenance_mode'); // 比如根据配置做维护模式判断 if ($maintenanceMode === 'true') { // 处理逻辑... } } }
然后在services.yaml里注册这个监听器:
services: # ... 其他服务 App\EventListener\ConfigListener: arguments: $container: '@service_container' tags: - { name: kernel.event_listener, event: kernel.request, method: onKernelRequest }
额外优化:配置更新时自动清缓存
如果数据库里的配置更新了,缓存不会自动刷新,所以可以给Config实体加个生命周期监听器,当配置保存/更新时清除对应缓存:
// src/EventListener/ConfigCacheClearListener.php namespace App\EventListener; use App\Entity\Config; use Doctrine\ORM\Event\PostPersistEventArgs; use Doctrine\ORM\Event\PostUpdateEventArgs; use Symfony\Contracts\Cache\CacheInterface; class ConfigCacheClearListener { private $cache; public function __construct(CacheInterface $cache) { $this->cache = $cache; } public function postPersist(PostPersistEventArgs $args) { $this->clearCache($args->getObject()); } public function postUpdate(PostUpdateEventArgs $args) { $this->clearCache($args->getObject()); } private function clearCache($entity) { if ($entity instanceof Config) { $this->cache->delete('config_'.$entity->getKey()); } } }
注册这个监听器:
services: # ... 其他服务 App\EventListener\ConfigCacheClearListener: arguments: $cache: '@cache.app' tags: - { name: doctrine.event_listener, event: postPersist } - { name: doctrine.event_listener, event: postUpdate }
这样就完美解决了缓存更新的问题。
内容的提问来源于stack exchange,提问作者jcarlosweb
相关产品推荐
相关产品推荐

