madmis / activity-log-bundle
活动日志组件 - 扩展 doctrine loggable 组件
Requires
Requires (Dev)
- phpunit/phpunit: ^5.3
README
ActivityLogBundle - 扩展 doctrine loggable (StofDoctrineExtensionsBundle)
包含内容
ActivityLogBundle 使用来自 StofDoctrineExtensionsBundle 和 DoctrineExtensions 的 Loggable 扩展,并扩展了以下字段
Gedmo\Loggable\Entity\MappedSuperclass\AbstractLogEntry 以下字段:
- parentId - 存储“主实体”的依赖关系
- parentClass - 存储“主实体”类型
- oldData - 发生变化的数据
- name - 条目名称(显示在活动日志中)
- user - 与更改数据的用户的关联映射
Bundle 包含扩展的监听器(LoggableListener)以处理上述字段。
还提供格式化器,用于在视图(HTML)中显示活动日志之前进行预处理。
安装
使用 Composer 非常简单,运行
composer require madmis/activity-log-bundle
然后在内核中启用组件
public function registerBundles() { $bundles = [ // ... new ActivityLogBundle\ActivityLogBundle(), // ... ]; ... }
配置组件
# app/config/config.yml doctrine: dbal: #... orm: #... resolve_target_entities: Symfony\Component\Security\Core\User\UserInterface: AppBundle\Entity\User mappings: gedmo_loggable: type: annotation prefix: Gedmo\Loggable\Entity dir: "%kernel.root_dir%/../src/AppBundle/Entity/" alias: GedmoLoggable is_bundle: false stof_doctrine_extensions: class: loggable: ActivityLogBundle\Listener\LoggableListener orm: default: loggable: true
创建实体并使其可记录
namespace AppBundle\Entity; use Doctrine\ORM\Mapping as ORM; use Gedmo\Mapping\Annotation as Gedmo; use ActivityLogBundle\Entity\Interfaces\StringableInterface; /** * @package AppBundle\Entity * @ORM\Entity(repositoryClass="ProjectRepository") * @ORM\Table * @Gedmo\Loggable(logEntryClass="ActivityLogBundle\Entity\LogEntry") */ class Project implements StringableInterface { /** * @var int * @ORM\Id * @ORM\Column(type="integer") * @ORM\GeneratedValue(strategy="AUTO") */ private $id; /** * @var string * @ORM\Column(type="string", length=128) * @Gedmo\Versioned */ private $name; /** * @var string * @ORM\Column(type="string", length=16) * @Gedmo\Versioned */ private $key; //...
StringableInterface 是保存 LogEntry::name 所必需的。
然后运行命令更新数据库模式
php bin/console doctrine:schema:update --force
使用格式化器查看数据
格式化器类: ActivityLogBundle\Service\ActivityLog\ActivityLogFormatter 格式化器服务: activity_log.formatter
所需: LoggerInterface 作为依赖项
默认情况下,没有自定义格式化器类的实体使用 ActivityLogBundle\Service\ActivityLog\EntityFormatter\UniversalFormatter 格式化。
但是您可以为每个实体实现自定义格式化器。
要注册自定义格式化器,添加以下属性的服务标签(必需)
- name: 'activity_log.formatter'
- entity: 应由注册的格式化器格式化的实体的类名
示例
services: app.formatter.project: class: AppBundle\Service\ActivityFormatter\Project tags: - { name: activity_log.formatter, entity: 'Project'}
例如,对于 AppBundle\Entity\Project 实体
namespace AppBundle\Service\ActivityFormatter; class Project extends AbstractFormatter implements FormatterInterface { /** * @param LogEntryInterface $log * @return array */ public function format(LogEntryInterface $log) { $result = $log->toArray(); if ($log->isCreate()) { $result['message'] = sprintf('The <b>Project <span class="font-green-jungle">"%s"</span></b> was created.', $log->getName()); } else if ($log->isRemove()) { $result['message'] = sprintf('The <b>Project <span class="font-red-flamingo">"%s"</span></b> was removed.', $log->getName()); } else if ($log->isUpdate()) { $result['message'] = '<dl><dt>The <b>Project <span class="font-yellow-gold">"%s"</span></b> was updated.</dt>%s</dl>'; $data = $log->getData(); $oldData = $log->getOldData(); $text = ''; foreach ($data as $field => $value) { $value = $this->normalizeValue($field, $value); if (array_key_exists($field, $oldData)) { $oldValue = $this->normalizeValue($field, $oldData[$field]); $subText = sprintf('from "<b>%s</b>" to "<b>%s</b>".', $oldValue, $value); } else { $subText = sprintf('to "<b>%s</b>".', $value); } $text .= sprintf('<dd>Property "<b>%s</b>" was changed: %s</dd>', $field, $subText); } $result['message'] = sprintf($result['message'], $log->getName(), $text); } else { $result['message'] = "Undefined action: {$log->getAction()}."; } return $result; } }
如果实体与其他实体有关联,则可以通过 AbstractFormatter::normalizeValue 解决。该方法调用实体格式化器类中的方法,该方法名称与适当属性相匹配。
例如,Project 实体具有与 Type 实体的 ManyToOne 关联映射。要获取 Type 名称,我们可以在 Project 格式化器中添加 type 方法
namespace AppBundle\Service\ActivityFormatter; class Project extends AbstractFormatter implements FormatterInterface { //... /** * @param array $value * @return string */ protected function type(array $value) { if (isset($value['id'])) { /** @var Type $entity */ $entity = $this->entityManager->getRepository('AppBundle:Type') ->find($value['id']); if ($entity) { return $entity->getName(); } } return ''; }
结果是我们有格式化响应以在视图中显示。
在控制器中使用活动日志
$em = $this->getDoctrine()->getManager(); // get log entries for entity $entries = $em ->getRepository('AppBundle:LogEntry') ->getLogEntriesQueryBuilder($entity) ->getQuery() ->getResult(); // format log entries to show in the view $entries = $this ->get('activity_log.formatter') ->format($entries);
对于 $entity
应配置 实体格式化器。