<?php
namespace ProjectBiz\DatabaseBundle\Database;
use Doctrine\DBAL\Connection;
use Doctrine\DBAL\Query\QueryBuilder;
use Doctrine\ORM\EntityRepository;
use ProjectBiz\DatabaseBundle\Entity\ColumnDefinition;
use ProjectBiz\DatabaseBundle\Form\Constraints\DateTimeConstraint;
use ProjectBiz\DatabaseBundle\Form\Constraints\UniqueConstraint;
use Symfony\Component\Validator\Constraints\NotNull;
use Symfony\Contracts\Translation\TranslatorInterface;
abstract class TableAndViewInfo implements TableInfoInterface
{
protected static $columnDescriptions = [];
/**
* @var Connection
*/
protected $tablename;
protected $databaseSchemaCache;
protected $tableHelper;
protected $userRights;
/**
* @var \Symfony\Component\Validator\Constraint[]
*/
protected $constraints = [];
private $cachedReadableColumns = [];
private $cachedWriteableColumns = [];
private $cachedTableConstraints;
static private $cachedTableDefinition = null;
/**
* Construct.
*
* @param Connection $connection
* @param $tablename
* @param EntityRepository $columnDefinitionRepository
* @param $prefix
*/
public function __construct(
$tablename,
DatabaseSchemaCache $databaseSchemaCache,
TableHelper $tableHelper,
TranslatorInterface $translator
) {
$this->tablename = $tablename;
$this->databaseSchemaCache = $databaseSchemaCache;
$this->tableHelper = $tableHelper;
$this->translator = $translator;
$this->userRights = $this->tableHelper->securityContext->getUser() ? $this->tableHelper->securityContext->getUser()->getRights()->getRights() : null;
}
/**
* @return string
*/
public function getCaption()
{
$tableDefinitions = $this->databaseSchemaCache->getTableDefinitions();
if (isset($tableDefinitions[$this->getTablename()])) {
if (isset($tableDefinitions[$this->getTablename()]['TableDefinition_Caption'])) {
return $tableDefinitions[$this->getTablename()]['TableDefinition_Caption'];
}
}
return $this->getTablename();
}
/**
* Return the referenced columns of other tables
*
* @param type $columns
* @param type $columnName
* @param ColumnDefinition $columnDefinition
* @return string
*/
protected function addReferencedColumns($columns, $columnName, ColumnDefinition $columnDefinition)
{
$type = $columnDefinition->getType();
if (($type === 'link' || $type === 'file' || $type === null ) && (null !== $columnDefinition->getSource())) {
$source = $columnDefinition->getSource();
$sourceTableInfo = $this->tableHelper->getTableInfo($source['table']);
$sourceColumnDefinitions = $sourceTableInfo->getColumnDefinitions();
/*
* Hide all referenced columns in view-editor when the user rights (of »TableDefinition_View_Edit_Permission«) are not sufficient. Show all columns if permissions are »NULL«.
*/
if ($sourceTableInfo->getViewEditPermissions() !== NULL && !$this->tableHelper->securityContext->checkRights($sourceTableInfo->getViewEditPermissions())) {
return $columns;
}
foreach ($sourceColumnDefinitions as $columnDefinition) {
/*
* Hide the referenced column in view-editor when the user rights are not sufficient.
*/
if ($this->userRights && !$columnDefinition->checkReadRights($this->userRights)) {
continue;
}
$sourceColumnName = $columnName . ':' . $columnDefinition->getColumn();
$columns[] = $sourceColumnName;
}
return $columns;
}
return $columns;
}
/**
* @return string|null
*/
public function getDescription()
{
$tableDefinitions = $this->databaseSchemaCache->getTableDefinitions();
if (isset($tableDefinitions[$this->getTablename()])) {
if (isset($tableDefinitions[$this->getTablename()]['TableDefinition_Description'])) {
return $tableDefinitions[$this->getTablename()]['TableDefinition_Description'];
}
}
return null;
}
public function hasGenericEditPermission($rights)
{
$tableDefinitions = $this->databaseSchemaCache->getTableDefinitions();
if (isset($tableDefinitions[$this->getTablename()])) {
$user_rights = gmp_init($rights);
$permissions = gmp_init($tableDefinitions[$this->getTablename()]['TableDefinition_GenericEdit_Permission']);
return gmp_cmp(gmp_and($user_rights, $permissions), '0') > 0;
}
return false;
}
/**
* @inheritdoc
*/
abstract public function buildFrom(QueryBuilder $builder, $mainTableName = 'mt');
/**
* @inheritdoc
*/
public function isReadable($column, $rights)
{
$parts = explode(':', $column);
$numParts = count($parts);
switch ($numParts) {
case 1:
return in_array($parts[0], $this->getReadableColumns($rights));
case 2:
if (!in_array($parts[0], $this->getReadableColumns($rights))) {
return false;
}
$colDef = $this->getColumnDefinitions()[$parts[0]];
$source = $colDef->getSource();
if ((null === $source) || !array_key_exists('table', $source)) {
return false;
}
$sourceTableInfo = $this->tableHelper->getTableInfo($source['table']);
if (null === $sourceTableInfo) {
return false;
}
return in_array($parts[1], $sourceTableInfo->getReadableColumns($rights));
case 0:
default:
return false;
}
}
/**
* @inheritdoc
*/
public function getReadableColumns($rights)
{
if (!isset($this->cachedReadableColumns[$rights])) {
$readableColumns = [];
$colDefs = $this->getColumnDefinitions();
foreach ($this->getColumns() as $column) {
$defName = (new Column($column, 'view'))->getDefinitionName();
if (
isset($colDefs[$defName]) &&
$colDefs[$defName]->checkReadRights($rights)
) {
$readableColumns[] = $column;
}
}
$this->cachedReadableColumns[$rights] = $readableColumns;
}
return $this->cachedReadableColumns[$rights];
}
/**
* @inheritdoc
*/
abstract public function getColumnDefinitions();
/**
* @inheritdoc
*/
public function getColumnDefinition($viewName)
{
$colDefs = $this->getColumnDefinitions();
if (strpos($viewName, ':') !== false) {
$parts = explode(':', $viewName);
$column = new Column($parts[0], 'view');
if (!isset($colDefs[$column->getDefinitionName()])) {
throw new \Exception('Missing ColumnDefinition');
}
$sourceTableInfo = $this->getSourceTableInfo($column->getDefinitionName());
return $sourceTableInfo->getColumnDefinition($parts[1]);
} else {
$column = new Column($viewName, 'view');
return $colDefs[$column->getDefinitionName()];
}
}
/**
* @inheritdoc
*/
abstract public function getColumns();
/**
* @inheritdoc
*/
abstract public function getColumnSelectionForView();
/**
* @inheritdoc
*/
public function isWriteable($column, $rights)
{
return in_array($column, $this->getWriteableColumns($rights));
}
/**
* @inheritdoc
*/
public function getWriteableColumns($rights)
{
if (!isset($this->cachedWriteableColumns[$rights])) {
$writeableColumns = [];
$colDefs = $this->getColumnDefinitions();
foreach ($this->getColumns() as $column) {
$defName = (new Column($column, 'view'))->getDefinitionName();
if (
isset($colDefs[$defName]) &&
$colDefs[$defName]->checkWriteRights($rights)
) {
$writeableColumns[] = $column;
}
}
$this->cachedWriteableColumns[$rights] = $writeableColumns;
}
return $this->cachedWriteableColumns[$rights];
}
/**
* @inheritdoc
*/
public function getTableConstraints($repo)
{
if (!isset($this->cachedTableConstraints)) {
$this->cachedTableConstraints = $this->buildTableConstraints($repo);
}
return $this->cachedTableConstraints;
}
protected function buildTableConstraints($repo)
{
$indices = $this->databaseSchemaCache->getIndices($this->getTablename());
$constraints = [];
foreach ($indices as $index) {
if ($index->isUnique()) {
$constraints[] = new UniqueConstraint($repo, $index->getColumns());
}
}
return $constraints;
}
/**
* @inheritdoc
*/
public function getTablename()
{
return $this->tablename;
}
/**
* @inheritdoc
*/
public function getColumnConstraints($column)
{
if (!isset($this->constraints[$column])) {
$this->constraints[$column] = $this->buildConstraints($column);
}
return $this->constraints[$column];
}
/**
* Automatically build constraints based on the database table description and the values that are set
* in the ColumnDefinitions.
*
* @param $column
*
* @return array
*/
protected function buildConstraints($column)
{
// Build database based contraints
$constraints = [];
$defColumnName = (new Column($column, 'view'))->getDefinitionName();
$columnDesc = $this->describeColumn($column);
if (isset($columnDesc)) {
if ($columnDesc->getNotnull() && ($defColumnName != $this->getPrimaryKey())) {
$constraints[] = new NotNull();
}
}
// Build ColumnDefinitionsConstraints
$columnDefinitions = $this->getColumnDefinitions();
if (isset($columnDefinitions[$defColumnName])) {
if (
($columnDefinitions[$defColumnName]->getType() == 'datetime') ||
($columnDefinitions[$defColumnName]->getType() == 'date')
) {
// Add datetime constraint
$constraints[] = new DateTimeConstraint();
}
}
return $constraints;
}
/**
* @inheritdoc
*/
public function describeColumn($column)
{
if (!in_array($column, $this->getColumns())) {
return null;
}
$columnDefinitions = $this->getColumnDefinitions();
$defColumnName = (new Column($column, 'view'))->getDefinitionName();
if (!isset($columnDefinitions[$defColumnName])) {
return null;
}
if ($columnDefinitions[$defColumnName]->isVirtual()) {
return null;
}
$tablename = $columnDefinitions[$defColumnName]->getTable();
$columns = $this->getColumnsForTable($tablename);
$lowerColumnName = strtolower($defColumnName);
if (isset($columns[$lowerColumnName])) {
return $columns[$lowerColumnName];
}
return null;
}
/**
* @param $tablename
*
* @return \Doctrine\DBAL\Schema\Column[]
*/
protected function getColumnsForTable($tablename)
{
return $this->databaseSchemaCache->getColumnsForTable($tablename);
}
/**
* @inheritdoc
*/
abstract public function getPrimaryKey();
public function getSourceTableInfo($column)
{
$colDefs = $this->getColumnDefinitions();
if (!array_key_exists($column, $colDefs)) {
return null;
}
$colDef = $colDefs[$column];
$source = $colDef->getSource();
if ((null === $source) || (!array_key_exists('table', $source))) {
return null;
}
return $this->tableHelper->getTableInfo($source['table']);
}
public function getLabelForViewColumn($columnName)
{
$parts = explode(':', $columnName);
$numParts = count($parts);
switch ($numParts) {
case 1:
$column = new Column($columnName, 'view');
$colDefs = $this->getColumnDefinitions();
if (!array_key_exists($column->getDefinitionName(), $colDefs)) {
return $columnName;
}
/*
* Return the caption and translate it at once.
*/
return $this->translator->trans($colDefs[$column->getDefinitionName()]->getCaption());
case 2:
$name = $this->getLabelForViewColumn($parts[0]);
$column = new Column($parts[0], 'view');
$sourceTableInfo = $this->getSourceTableInfo($column->getDefinitionName());
$name = $name.': '.(is_null($sourceTableInfo) ? '?' : $sourceTableInfo->getLabelForViewColumn(
$parts[1]
));
return $name;
}
}
public function getViewEditPermissions() {
$tableDefinitions = $this->databaseSchemaCache->getTableDefinitions();
if (isset($tableDefinitions[$this->getTablename()])) {
return $tableDefinitions[$this->getTablename()]['TableDefinition_View_Edit_Permission'];
}
return null;
}
}