条令忽略了属性/列



我正在将一个基于ZendDb的应用程序迁移到条令2。

问题出在实体AuditLog上。在迁移之前,它被持久化为ZendDb(参见代码块1)。

现在实体AuditLog有多个子类,它们一起实现Single Table Inheritance模式(参见代码块2)。

既然我切换到了Doctrine,我只需要创建一个合适的AuditLog对象,并简单地创建persist(...)。事实上,这就是我正在尝试的(参见代码块3)。但现在我遇到了AuditLog的属性$resourceId的问题:Doctrine似乎忽略了它。该属性包含正确的值(我在调试器中看到了它),但INSERT语句没有得到它,看起来像:

INSERT INTO audit_log
(resource_id, action, datetime, user_id, resource_type)
VALUES
(NULL, 'order.created', NULL, 1, 'order');

结果是:实体被持久化,但resource_id为空。

为什么Doctrine忽略了这一属性,以及如何保存它


代码

1ZendDb的持久性

AuditLogger

class AuditLogger extends AbstractPlugin
{
...
public function log($resourceType = null, $resourceId = null, $action = null, $userId = null)
{
$auditLog = new AuditLog();
$auditLog->setResourceType($resourceType);
$auditLog->setResourceId($resourceId);
$auditLog->setAction($action);
...
$auditLog->setUser($this->user);
$this->auditLogService->create($auditLog);
// The AuditLogService calls then the AuditLogMapper#create(...).
}
}

AuditLogMapper

class AuditLogMapper extends AbstractMapper implements AuditLogMapperInterface
{
...
public function create(AuditLog $dataObject)
{
$data = [];
// data retrieved directly from the input
$data['resource_type'] = $dataObject->getResourceType();
$data['resource_id'] = $dataObject->getResourceId();
$data['action'] = $dataObject->getAction();
$data['datetime'] = $dataObject->getDatetime();
$data['user_id'] = $dataObject->getUser()->getId();
$action = new Insert('audit_log');
unset($data['id']);
$action->values($data);
$sql = new Sql($this->dbAdapter);
$statement = $sql->prepareStatementForSqlObject($action);
$result = $statement->execute();
if ($result instanceof ResultInterface) {
$newId = $result->getGeneratedValue() ?: $dataObject->getId();
if ($newId) {
$dataObject->setId($newId);
}
return $dataObject;
}
throw new Exception('Database error in ' . __METHOD__);
}
}

2实体

AuditLog

use DoctrineORMMapping as ORM;
/**
* AuditLog
*
* @ORMTable(
*     name="audit_log",
*     indexes={
*         @ORMIndex(name="fk_audit_log_user_idx", columns={"user_id"})
*     }
* )
* @ORMEntity
* @ORMInheritanceType("SINGLE_TABLE")
* @ORMDiscriminatorColumn(name="resource_type", type="string")
* @ORMDiscriminatorMap({
*     "" = "AuditLog",
*     "order" = "AuditLogOrder",
*     "server" = "AuditLogServer",
*     "cluster" = "AuditLogCluster"
* })
*/
class AuditLog extends AbstractDataObject
{
/** @var string */
const RESSOURCE_TYPE_ORDER = 'order';
/** @var string */
const RESSOURCE_TYPE_SERVER = 'server';
/** @var string */
const RESSOURCE_TYPE_CLUSTER = 'cluster';
/** @var string */
const ACTION_ORDER_CREATED = 'order.created';
/** @var string */
const ACTION_ORDER_SUBMITTED = 'order.submitted';
/** @var string */
const ACTION_ORDER_EDITING_STARTED = 'order.editing_started';
/** @var string */
const ACTION_ORDER_UPDATED = 'order.updated';
/** @var string */
const ACTION_ORDER_CANCELED = 'order.canceled';
/** @var string */
const ACTION_ORDER_CHECKING_STARTED = 'order.checking_started';
/** @var string */
const ACTION_ORDER_ACCEPTED = 'order.accepted';
/** @var string */
const ACTION_ORDER_DECLINED = 'order.declined';
/** @var string */
const ACTION_ORDER_COMPLETED = 'order.completed';
/** @var string */
const ACTION_ORDER_EXPORTED = 'order.exported';
/** @var string */
const ACTION_SERVER_VIRTUAL_NODE_NAME_ADDED = 'server.virtual_node_name_added';
/** @var string */
const ACTION_CLUSTER_CREATED = 'cluster.created';
/**
* @var integer
*
* @ORMColumn(name="id", type="integer", nullable=false)
* @ORMId
* @ORMGeneratedValue(strategy="IDENTITY")
*/
protected $id;
/**
* @var string
*/
protected $resourceType;
/**
* @var string
*
* @ORMColumn(name="resource_id", type="string", length=50, nullable=true)
*/
protected $resourceId;
/**
* @var string
*
* @ORMColumn(name="action", type="string", nullable=true)
*/
protected $action;
/**
* @var DateTime
*
* @ORMColumn(name="datetime", type="datetime", nullable=false)
*/
protected $datetime;
/**
* @var User
*
* @ORMManyToOne(targetEntity="User")
*/
protected $user;
// access methods ...
}

AuditLogOrder

use DoctrineORMMapping as ORM;
/**
* AuditLogOrder
*
* @ORMTable(name="audit_log")
* @ORMEntity
*/
class AuditLogOrder extends AuditLog
{
/**
* @var Order
*
* @ORMManyToOne(targetEntity="Order")
* @ORMJoinColumn(name="resource_id", referencedColumnName="id")
*/
protected $order;
// access methods ...
}

AuditLogServer

use DoctrineORMMapping as ORM;
/**
* AuditLogServer
*
* @ORMTable(name="audit_log")
* @ORMEntity
*/
class AuditLogServer extends AuditLog
{
// ...
}

AuditLogCluster

use DoctrineORMMapping as ORM;
/**
* AuditLogCluster
*
* @ORMTable(name="audit_log")
* @ORMEntity
*/
class AuditLogCluster extends AuditLog
{
// ...
}

3坚持条令

AuditLogger

class AuditLogger extends AbstractPlugin
{
...
public function log($resourceType = null, $resourceId = null, $action = null, $userId = null)
{
switch ($resourceType) {
case AuditLog::RESSOURCE_TYPE_ORDER:
$auditLog = new AuditLogFileTransferRequest();
break;
case AuditLog::RESSOURCE_TYPE_SERVER:
$auditLog = new AuditLogServer();
break;
case AuditLog::RESSOURCE_TYPE_CLUSTER:
$auditLog = new AuditLogCluster();
break;
default:
$auditLog = new AuditLog();
}
$auditLog->setResourceType($resourceType);
$auditLog->setResourceId($resourceId);
$auditLog->setAction($action);
...
$auditLog->setUser($this->user);
$this->auditLogService->create($auditLog);
// The AuditLogService calls then the AuditLogMapper#create(...).
}
}

AuditLogMapper

class AuditLogMapper extends AbstractMapper implements AuditLogMapperInterface
{
...
public function create(AuditLog $dataObject)
{
$currentUser = $this->entityManager->getRepository(User::class)->find(
$dataObject->getUser()->getId()
);
$dataObject->setUser($currentUser);
$this->entityManager->persist($dataObject);
$this->entityManager->flush();
return $dataObject;
}
}

由于resource_id用作JoinColumn

/**
* @var Order
*
* @ORMManyToOne(targetEntity="Order")
* @ORMJoinColumn(name="resource_id", referencedColumnName="id")
*/
protected $order;

它不再是一个公共属性,可以直接设置。需要设置相关实体:

...
class AuditLogger extends AbstractPlugin
{
...
/**
* @var User
*/
protected $user;
public function __construct(
AuditLogServiceInterface $auditLogService,
OrderInterface $order,
ServerServiceInterface $serverService,
ClusterServiceInterface $clusterService,
User $user = null
) {
$this->auditLogService = $auditLogService;
$this->order = $order;
$this->serverService = $serverService;
$this->clusterService = $clusterService;
$this->user = $user;
}
public function log($resourceType = null, $resourceId = null, $action = null, $userId = null)
{
switch ($resourceType) {
case AuditLog::RESSOURCE_TYPE_ORDER:
$auditLog = new AuditLogFileTransferRequest();
$resource = $this->order->findOne($resourceId);
$auditLog->setFileTransferRequest($resource);
break;
case AuditLog::RESSOURCE_TYPE_SERVER:
$auditLog = new AuditLogServer();
$resource = $this->serverService->findOne($resourceId);
$auditLog->setServer($resource);
break;
case AuditLog::RESSOURCE_TYPE_CLUSTER:
$auditLog = new AuditLogCluster();
$resource = $this->clusterService->findOne($resourceId);
$auditLog->setCluster($resource);
break;
default:
$auditLog = new AuditLog();
}
$auditLog->setAction($action);
if ($userId) {
$user = new User();
$user->setId($userId);
$auditLog->setUser($user);
} elseif ($this->user) {
$auditLog->setUser($this->user);
}
$this->auditLogService->create($auditLog);
}
}

相关内容

  • 没有找到相关文章

最新更新