"Fossies" - the Fresh Open Source Software Archive

Member "drupal-8.9.10/core/lib/Drupal/Core/Entity/Sql/DefaultTableMapping.php" (26 Nov 2020, 22970 Bytes) of package /linux/www/drupal-8.9.10.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) PHP source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "DefaultTableMapping.php" see the Fossies "Dox" file reference documentation and the last Fossies "Diffs" side-by-side code changes report: 9.0.8_vs_9.1.0-rc1.

    1 <?php
    2 
    3 namespace Drupal\Core\Entity\Sql;
    4 
    5 use Drupal\Core\Entity\ContentEntityTypeInterface;
    6 use Drupal\Core\Entity\EntityTypeInterface;
    7 use Drupal\Core\Field\FieldStorageDefinitionInterface;
    8 
    9 /**
   10  * Defines a default table mapping class.
   11  */
   12 class DefaultTableMapping implements TableMappingInterface {
   13 
   14   /**
   15    * The entity type definition.
   16    *
   17    * @var \Drupal\Core\Entity\ContentEntityTypeInterface
   18    */
   19   protected $entityType;
   20 
   21   /**
   22    * The field storage definitions of this mapping.
   23    *
   24    * @var \Drupal\Core\Field\FieldStorageDefinitionInterface[]
   25    */
   26   protected $fieldStorageDefinitions = [];
   27 
   28   /**
   29    * The prefix to be used by all the tables of this mapping.
   30    *
   31    * @var string
   32    */
   33   protected $prefix;
   34 
   35   /**
   36    * The base table of the entity.
   37    *
   38    * @var string
   39    */
   40   protected $baseTable;
   41 
   42   /**
   43    * The table that stores revisions, if the entity supports revisions.
   44    *
   45    * @var string
   46    */
   47   protected $revisionTable;
   48 
   49   /**
   50    * The table that stores field data, if the entity has multilingual support.
   51    *
   52    * @var string
   53    */
   54   protected $dataTable;
   55 
   56   /**
   57    * The table that stores revision field data if the entity supports revisions
   58    * and has multilingual support.
   59    *
   60    * @var string
   61    */
   62   protected $revisionDataTable;
   63 
   64   /**
   65    * A list of field names per table.
   66    *
   67    * This corresponds to the return value of
   68    * TableMappingInterface::getFieldNames() except that this variable is
   69    * additionally keyed by table name.
   70    *
   71    * @var array[]
   72    */
   73   protected $fieldNames = [];
   74 
   75   /**
   76    * A list of database columns which store denormalized data per table.
   77    *
   78    * This corresponds to the return value of
   79    * TableMappingInterface::getExtraColumns() except that this variable is
   80    * additionally keyed by table name.
   81    *
   82    * @var array[]
   83    */
   84   protected $extraColumns = [];
   85 
   86   /**
   87    * A mapping of column names per field name.
   88    *
   89    * This corresponds to the return value of
   90    * TableMappingInterface::getColumnNames() except that this variable is
   91    * additionally keyed by field name.
   92    *
   93    * This data is derived from static::$storageDefinitions, but is stored
   94    * separately to avoid repeated processing.
   95    *
   96    * @var array[]
   97    */
   98   protected $columnMapping = [];
   99 
  100   /**
  101    * A list of all database columns per table.
  102    *
  103    * This corresponds to the return value of
  104    * TableMappingInterface::getAllColumns() except that this variable is
  105    * additionally keyed by table name.
  106    *
  107    * This data is derived from static::$storageDefinitions, static::$fieldNames,
  108    * and static::$extraColumns, but is stored separately to avoid repeated
  109    * processing.
  110    *
  111    * @var array[]
  112    */
  113   protected $allColumns = [];
  114 
  115   /**
  116    * Constructs a DefaultTableMapping.
  117    *
  118    * @param \Drupal\Core\Entity\ContentEntityTypeInterface $entity_type
  119    *   The entity type definition.
  120    * @param \Drupal\Core\Field\FieldStorageDefinitionInterface[] $storage_definitions
  121    *   A list of field storage definitions that should be available for the
  122    *   field columns of this table mapping.
  123    * @param string $prefix
  124    *   (optional) A prefix to be used by all the tables of this mapping.
  125    *   Defaults to an empty string.
  126    */
  127   public function __construct(ContentEntityTypeInterface $entity_type, array $storage_definitions, $prefix = '') {
  128     $this->entityType = $entity_type;
  129     $this->fieldStorageDefinitions = $storage_definitions;
  130     $this->prefix = $prefix;
  131 
  132     // @todo Remove table names from the entity type definition in
  133     //   https://www.drupal.org/node/2232465.
  134     $this->baseTable = $this->prefix . $entity_type->getBaseTable() ?: $entity_type->id();
  135     if ($entity_type->isRevisionable()) {
  136       $this->revisionTable = $this->prefix . $entity_type->getRevisionTable() ?: $entity_type->id() . '_revision';
  137     }
  138     if ($entity_type->isTranslatable()) {
  139       $this->dataTable = $this->prefix . $entity_type->getDataTable() ?: $entity_type->id() . '_field_data';
  140     }
  141     if ($entity_type->isRevisionable() && $entity_type->isTranslatable()) {
  142       $this->revisionDataTable = $this->prefix . $entity_type->getRevisionDataTable() ?: $entity_type->id() . '_field_revision';
  143     }
  144   }
  145 
  146   /**
  147    * Initializes the table mapping.
  148    *
  149    * @param \Drupal\Core\Entity\ContentEntityTypeInterface $entity_type
  150    *   The entity type definition.
  151    * @param \Drupal\Core\Field\FieldStorageDefinitionInterface[] $storage_definitions
  152    *   A list of field storage definitions that should be available for the
  153    *   field columns of this table mapping.
  154    * @param string $prefix
  155    *   (optional) A prefix to be used by all the tables of this mapping.
  156    *   Defaults to an empty string.
  157    *
  158    * @return static
  159    *
  160    * @internal
  161    */
  162   public static function create(ContentEntityTypeInterface $entity_type, array $storage_definitions, $prefix = '') {
  163     $table_mapping = new static($entity_type, $storage_definitions, $prefix);
  164 
  165     $revisionable = $entity_type->isRevisionable();
  166     $translatable = $entity_type->isTranslatable();
  167 
  168     $id_key = $entity_type->getKey('id');
  169     $revision_key = $entity_type->getKey('revision');
  170     $bundle_key = $entity_type->getKey('bundle');
  171     $uuid_key = $entity_type->getKey('uuid');
  172     $langcode_key = $entity_type->getKey('langcode');
  173 
  174     $shared_table_definitions = array_filter($storage_definitions, function (FieldStorageDefinitionInterface $definition) use ($table_mapping) {
  175       return $table_mapping->allowsSharedTableStorage($definition);
  176     });
  177 
  178     $key_fields = array_values(array_filter([$id_key, $revision_key, $bundle_key, $uuid_key, $langcode_key]));
  179     $all_fields = array_keys($shared_table_definitions);
  180     $revisionable_fields = array_keys(array_filter($shared_table_definitions, function (FieldStorageDefinitionInterface $definition) {
  181       return $definition->isRevisionable();
  182     }));
  183     // Make sure the key fields come first in the list of fields.
  184     $all_fields = array_merge($key_fields, array_diff($all_fields, $key_fields));
  185 
  186     $revision_metadata_fields = $revisionable ? array_values($entity_type->getRevisionMetadataKeys()) : [];
  187     $revision_metadata_fields = array_intersect($revision_metadata_fields, array_keys($storage_definitions));
  188 
  189     if (!$revisionable && !$translatable) {
  190       // The base layout stores all the base field values in the base table.
  191       $table_mapping->setFieldNames($table_mapping->baseTable, $all_fields);
  192     }
  193     elseif ($revisionable && !$translatable) {
  194       // The revisionable layout stores all the base field values in the base
  195       // table, except for revision metadata fields. Revisionable fields
  196       // denormalized in the base table but also stored in the revision table
  197       // together with the entity ID and the revision ID as identifiers.
  198       $table_mapping->setFieldNames($table_mapping->baseTable, array_diff($all_fields, $revision_metadata_fields));
  199       $revision_key_fields = [$id_key, $revision_key];
  200       $table_mapping->setFieldNames($table_mapping->revisionTable, array_merge($revision_key_fields, $revisionable_fields));
  201     }
  202     elseif (!$revisionable && $translatable) {
  203       // Multilingual layouts store key field values in the base table. The
  204       // other base field values are stored in the data table, no matter
  205       // whether they are translatable or not. The data table holds also a
  206       // denormalized copy of the bundle field value to allow for more
  207       // performant queries. This means that only the UUID is not stored on
  208       // the data table.
  209       $table_mapping
  210         ->setFieldNames($table_mapping->baseTable, $key_fields)
  211         ->setFieldNames($table_mapping->dataTable, array_values(array_diff($all_fields, [$uuid_key])));
  212     }
  213     elseif ($revisionable && $translatable) {
  214       // The revisionable multilingual layout stores key field values in the
  215       // base table and the revision table holds the entity ID, revision ID and
  216       // langcode ID along with revision metadata. The revision data table holds
  217       // data field values for all the revisionable fields and the data table
  218       // holds the data field values for all non-revisionable fields. The data
  219       // field values of revisionable fields are denormalized in the data
  220       // table, as well.
  221       $table_mapping->setFieldNames($table_mapping->baseTable, $key_fields);
  222 
  223       // Like in the multilingual, non-revisionable case the UUID is not
  224       // in the data table. Additionally, do not store revision metadata
  225       // fields in the data table.
  226       $data_fields = array_values(array_diff($all_fields, [$uuid_key], $revision_metadata_fields));
  227       $table_mapping->setFieldNames($table_mapping->dataTable, $data_fields);
  228 
  229       $revision_base_fields = array_merge([$id_key, $revision_key, $langcode_key], $revision_metadata_fields);
  230       $table_mapping->setFieldNames($table_mapping->revisionTable, $revision_base_fields);
  231 
  232       $revision_data_key_fields = [$id_key, $revision_key, $langcode_key];
  233       $revision_data_fields = array_diff($revisionable_fields, $revision_metadata_fields, [$langcode_key]);
  234       $table_mapping->setFieldNames($table_mapping->revisionDataTable, array_merge($revision_data_key_fields, $revision_data_fields));
  235     }
  236 
  237     // Add dedicated tables.
  238     $dedicated_table_definitions = array_filter($table_mapping->fieldStorageDefinitions, function (FieldStorageDefinitionInterface $definition) use ($table_mapping) {
  239       return $table_mapping->requiresDedicatedTableStorage($definition);
  240     });
  241     $extra_columns = [
  242       'bundle',
  243       'deleted',
  244       'entity_id',
  245       'revision_id',
  246       'langcode',
  247       'delta',
  248     ];
  249     foreach ($dedicated_table_definitions as $field_name => $definition) {
  250       $tables = [$table_mapping->getDedicatedDataTableName($definition)];
  251       if ($revisionable && $definition->isRevisionable()) {
  252         $tables[] = $table_mapping->getDedicatedRevisionTableName($definition);
  253       }
  254       foreach ($tables as $table_name) {
  255         $table_mapping->setFieldNames($table_name, [$field_name]);
  256         $table_mapping->setExtraColumns($table_name, $extra_columns);
  257       }
  258     }
  259 
  260     return $table_mapping;
  261   }
  262 
  263   /**
  264    * Gets the base table name.
  265    *
  266    * @return string
  267    *   The base table name.
  268    *
  269    * @internal
  270    */
  271   public function getBaseTable() {
  272     return $this->baseTable;
  273   }
  274 
  275   /**
  276    * Gets the revision table name.
  277    *
  278    * @return string|null
  279    *   The revision table name.
  280    *
  281    * @internal
  282    */
  283   public function getRevisionTable() {
  284     return $this->revisionTable;
  285   }
  286 
  287   /**
  288    * Gets the data table name.
  289    *
  290    * @return string|null
  291    *   The data table name.
  292    *
  293    * @internal
  294    */
  295   public function getDataTable() {
  296     return $this->dataTable;
  297   }
  298 
  299   /**
  300    * Gets the revision data table name.
  301    *
  302    * @return string|null
  303    *   The revision data table name.
  304    *
  305    * @internal
  306    */
  307   public function getRevisionDataTable() {
  308     return $this->revisionDataTable;
  309   }
  310 
  311   /**
  312    * {@inheritdoc}
  313    */
  314   public function getTableNames() {
  315     return array_unique(array_merge(array_keys($this->fieldNames), array_keys($this->extraColumns)));
  316   }
  317 
  318   /**
  319    * {@inheritdoc}
  320    */
  321   public function getAllColumns($table_name) {
  322     if (!isset($this->allColumns[$table_name])) {
  323       $this->allColumns[$table_name] = [];
  324 
  325       foreach ($this->getFieldNames($table_name) as $field_name) {
  326         $this->allColumns[$table_name] = array_merge($this->allColumns[$table_name], array_values($this->getColumnNames($field_name)));
  327       }
  328 
  329       // There is just one field for each dedicated storage table, thus
  330       // $field_name can only refer to it.
  331       if (isset($field_name) && $this->requiresDedicatedTableStorage($this->fieldStorageDefinitions[$field_name])) {
  332         // Unlike in shared storage tables, in dedicated ones field columns are
  333         // positioned last.
  334         $this->allColumns[$table_name] = array_merge($this->getExtraColumns($table_name), $this->allColumns[$table_name]);
  335       }
  336       else {
  337         $this->allColumns[$table_name] = array_merge($this->allColumns[$table_name], $this->getExtraColumns($table_name));
  338       }
  339     }
  340     return $this->allColumns[$table_name];
  341   }
  342 
  343   /**
  344    * {@inheritdoc}
  345    */
  346   public function getFieldNames($table_name) {
  347     if (isset($this->fieldNames[$table_name])) {
  348       return $this->fieldNames[$table_name];
  349     }
  350     return [];
  351   }
  352 
  353   /**
  354    * {@inheritdoc}
  355    */
  356   public function getFieldTableName($field_name) {
  357     $result = NULL;
  358 
  359     if (isset($this->fieldStorageDefinitions[$field_name])) {
  360       // Since a field may be stored in more than one table, we inspect tables
  361       // in order of relevance: the data table if present is the main place
  362       // where field data is stored, otherwise the base table is responsible for
  363       // storing field data. Revision metadata is an exception as it's stored
  364       // only in the revision table.
  365       $storage_definition = $this->fieldStorageDefinitions[$field_name];
  366       $table_names = array_filter([
  367         $this->dataTable,
  368         $this->baseTable,
  369         $this->revisionTable,
  370         $this->getDedicatedDataTableName($storage_definition),
  371       ]);
  372 
  373       // Collect field columns.
  374       $field_columns = [];
  375       foreach (array_keys($storage_definition->getColumns()) as $property_name) {
  376         $field_columns[] = $this->getFieldColumnName($storage_definition, $property_name);
  377       }
  378 
  379       foreach ($table_names as $table_name) {
  380         $columns = $this->getAllColumns($table_name);
  381         // We assume finding one field column belonging to the mapping is enough
  382         // to identify the field table.
  383         if (array_intersect($columns, $field_columns)) {
  384           $result = $table_name;
  385           break;
  386         }
  387       }
  388     }
  389 
  390     if (!isset($result)) {
  391       throw new SqlContentEntityStorageException("Table information not available for the '$field_name' field.");
  392     }
  393 
  394     return $result;
  395   }
  396 
  397   /**
  398    * {@inheritdoc}
  399    */
  400   public function getColumnNames($field_name) {
  401     if (!isset($this->columnMapping[$field_name])) {
  402       $this->columnMapping[$field_name] = [];
  403       if (isset($this->fieldStorageDefinitions[$field_name]) && !$this->fieldStorageDefinitions[$field_name]->hasCustomStorage()) {
  404         foreach (array_keys($this->fieldStorageDefinitions[$field_name]->getColumns()) as $property_name) {
  405           $this->columnMapping[$field_name][$property_name] = $this->getFieldColumnName($this->fieldStorageDefinitions[$field_name], $property_name);
  406         }
  407       }
  408     }
  409     return $this->columnMapping[$field_name];
  410   }
  411 
  412   /**
  413    * {@inheritdoc}
  414    */
  415   public function getFieldColumnName(FieldStorageDefinitionInterface $storage_definition, $property_name) {
  416     $field_name = $storage_definition->getName();
  417 
  418     if ($this->allowsSharedTableStorage($storage_definition)) {
  419       $column_name = count($storage_definition->getColumns()) == 1 ? $field_name : $field_name . '__' . $property_name;
  420     }
  421     elseif ($this->requiresDedicatedTableStorage($storage_definition)) {
  422       if ($property_name == TableMappingInterface::DELTA) {
  423         $column_name = 'delta';
  424       }
  425       else {
  426         $column_name = !in_array($property_name, $this->getReservedColumns()) ? $field_name . '_' . $property_name : $property_name;
  427       }
  428     }
  429     else {
  430       throw new SqlContentEntityStorageException("Column information not available for the '$field_name' field.");
  431     }
  432 
  433     return $column_name;
  434   }
  435 
  436   /**
  437    * Adds field columns for a table to the table mapping.
  438    *
  439    * @param string $table_name
  440    *   The name of the table to add the field column for.
  441    * @param string[] $field_names
  442    *   A list of field names to add the columns for.
  443    *
  444    * @return $this
  445    *
  446    * @internal
  447    *
  448    * @todo Make this method protected in drupal:9.0.0.
  449    * @see https://www.drupal.org/node/3067336
  450    */
  451   public function setFieldNames($table_name, array $field_names) {
  452     $this->fieldNames[$table_name] = $field_names;
  453     // Force the re-computation of the column list.
  454     unset($this->allColumns[$table_name]);
  455     return $this;
  456   }
  457 
  458   /**
  459    * {@inheritdoc}
  460    */
  461   public function getExtraColumns($table_name) {
  462     if (isset($this->extraColumns[$table_name])) {
  463       return $this->extraColumns[$table_name];
  464     }
  465     return [];
  466   }
  467 
  468   /**
  469    * Adds a extra columns for a table to the table mapping.
  470    *
  471    * @param string $table_name
  472    *   The name of table to add the extra columns for.
  473    * @param string[] $column_names
  474    *   The list of column names.
  475    *
  476    * @return $this
  477    *
  478    * @internal
  479    *
  480    * @todo Make this method protected in drupal:9.0.0.
  481    * @see https://www.drupal.org/node/3067336
  482    */
  483   public function setExtraColumns($table_name, array $column_names) {
  484     $this->extraColumns[$table_name] = $column_names;
  485     // Force the re-computation of the column list.
  486     unset($this->allColumns[$table_name]);
  487     return $this;
  488   }
  489 
  490   /**
  491    * Checks whether the given field can be stored in a shared table.
  492    *
  493    * @param \Drupal\Core\Field\FieldStorageDefinitionInterface $storage_definition
  494    *   The field storage definition.
  495    *
  496    * @return bool
  497    *   TRUE if the field can be stored in a shared table, FALSE otherwise.
  498    */
  499   public function allowsSharedTableStorage(FieldStorageDefinitionInterface $storage_definition) {
  500     return !$storage_definition->hasCustomStorage() && $storage_definition->isBaseField() && !$storage_definition->isMultiple() && !$storage_definition->isDeleted();
  501   }
  502 
  503   /**
  504    * Checks whether the given field has to be stored in a dedicated table.
  505    *
  506    * @param \Drupal\Core\Field\FieldStorageDefinitionInterface $storage_definition
  507    *   The field storage definition.
  508    *
  509    * @return bool
  510    *   TRUE if the field has to be stored in a dedicated table, FALSE otherwise.
  511    */
  512   public function requiresDedicatedTableStorage(FieldStorageDefinitionInterface $storage_definition) {
  513     return !$storage_definition->hasCustomStorage() && !$this->allowsSharedTableStorage($storage_definition);
  514   }
  515 
  516   /**
  517    * Gets a list of dedicated table names for this mapping.
  518    *
  519    * @return string[]
  520    *   An array of table names.
  521    */
  522   public function getDedicatedTableNames() {
  523     $table_mapping = $this;
  524     $definitions = array_filter($this->fieldStorageDefinitions, function ($definition) use ($table_mapping) {
  525       return $table_mapping->requiresDedicatedTableStorage($definition);
  526     });
  527     $data_tables = array_map(function ($definition) use ($table_mapping) {
  528       return $table_mapping->getDedicatedDataTableName($definition);
  529     }, $definitions);
  530     $revision_tables = array_map(function ($definition) use ($table_mapping) {
  531       return $table_mapping->getDedicatedRevisionTableName($definition);
  532     }, $definitions);
  533     $dedicated_tables = array_merge(array_values($data_tables), array_values($revision_tables));
  534     return $dedicated_tables;
  535   }
  536 
  537   /**
  538    * {@inheritdoc}
  539    */
  540   public function getReservedColumns() {
  541     return ['deleted'];
  542   }
  543 
  544   /**
  545    * Generates a table name for a field data table.
  546    *
  547    * @param \Drupal\Core\Field\FieldStorageDefinitionInterface $storage_definition
  548    *   The field storage definition.
  549    * @param bool $is_deleted
  550    *   (optional) Whether the table name holding the values of a deleted field
  551    *   should be returned.
  552    *
  553    * @return string
  554    *   A string containing the generated name for the database table.
  555    */
  556   public function getDedicatedDataTableName(FieldStorageDefinitionInterface $storage_definition, $is_deleted = FALSE) {
  557     if ($is_deleted) {
  558       // When a field is a deleted, the table is renamed to
  559       // {field_deleted_data_UNIQUE_STORAGE_ID}. To make sure we don't end up
  560       // with table names longer than 64 characters, we hash the unique storage
  561       // identifier and return the first 10 characters so we end up with a short
  562       // unique ID.
  563       return "field_deleted_data_" . substr(hash('sha256', $storage_definition->getUniqueStorageIdentifier()), 0, 10);
  564     }
  565     else {
  566       return $this->generateFieldTableName($storage_definition, FALSE);
  567     }
  568   }
  569 
  570   /**
  571    * Generates a table name for a field revision archive table.
  572    *
  573    * @param \Drupal\Core\Field\FieldStorageDefinitionInterface $storage_definition
  574    *   The field storage definition.
  575    * @param bool $is_deleted
  576    *   (optional) Whether the table name holding the values of a deleted field
  577    *   should be returned.
  578    *
  579    * @return string
  580    *   A string containing the generated name for the database table.
  581    */
  582   public function getDedicatedRevisionTableName(FieldStorageDefinitionInterface $storage_definition, $is_deleted = FALSE) {
  583     if ($is_deleted) {
  584       // When a field is a deleted, the table is renamed to
  585       // {field_deleted_revision_UNIQUE_STORAGE_ID}. To make sure we don't end
  586       // up with table names longer than 64 characters, we hash the unique
  587       // storage identifier and return the first 10 characters so we end up with
  588       // a short unique ID.
  589       return "field_deleted_revision_" . substr(hash('sha256', $storage_definition->getUniqueStorageIdentifier()), 0, 10);
  590     }
  591     else {
  592       return $this->generateFieldTableName($storage_definition, TRUE);
  593     }
  594   }
  595 
  596   /**
  597    * Generates a safe and unambiguous field table name.
  598    *
  599    * The method accounts for a maximum table name length of 64 characters, and
  600    * takes care of disambiguation.
  601    *
  602    * @param \Drupal\Core\Field\FieldStorageDefinitionInterface $storage_definition
  603    *   The field storage definition.
  604    * @param bool $revision
  605    *   TRUE for revision table, FALSE otherwise.
  606    *
  607    * @return string
  608    *   The final table name.
  609    */
  610   protected function generateFieldTableName(FieldStorageDefinitionInterface $storage_definition, $revision) {
  611     // The maximum length of an entity type ID is 32 characters.
  612     $entity_type_id = substr($storage_definition->getTargetEntityTypeId(), 0, EntityTypeInterface::ID_MAX_LENGTH);
  613     $separator = $revision ? '_revision__' : '__';
  614 
  615     $table_name = $this->prefix . $entity_type_id . $separator . $storage_definition->getName();
  616     // Limit the string to 48 characters, keeping a 16 characters margin for db
  617     // prefixes.
  618     if (strlen($table_name) > 48) {
  619       // Use a shorter separator and a hash of the field storage unique
  620       // identifier.
  621       $separator = $revision ? '_r__' : '__';
  622       $field_hash = substr(hash('sha256', $storage_definition->getUniqueStorageIdentifier()), 0, 10);
  623 
  624       $table_name = $this->prefix . $entity_type_id . $separator . $field_hash;
  625 
  626       // If the resulting table name is still longer than 48 characters, use the
  627       // following pattern:
  628       // - prefix: max 34 chars;
  629       // - separator: max 4 chars;
  630       // - field_hash: max 10 chars.
  631       if (strlen($table_name) > 48) {
  632         $prefix = substr($this->prefix, 0, 34);
  633         $table_name = $prefix . $separator . $field_hash;
  634       }
  635     }
  636     return $table_name;
  637   }
  638 
  639 }