class OnlyOne in Allow a content type only once (Only One) 8
Class OnlyOne.
Hierarchy
- class \Drupal\onlyone\OnlyOne implements OnlyOneInterface uses StringTranslationTrait
Expanded class hierarchy of OnlyOne
1 file declares its use of OnlyOne
- OnlyOneTest.php in tests/
src/ Unit/ OnlyOneTest.php
3 string references to 'OnlyOne'
- onlyone.services.yml in ./
onlyone.services.yml - onlyone.services.yml
- OnlyOneConstraintValidatorTest::testValidation in tests/
src/ Kernel/ OnlyOneConstraintValidatorTest.php - Tests the OnlyOneConstraintValidator.
- onlyone_entity_type_alter in ./
onlyone.module - Implements hook_entity_type_alter().
1 service uses OnlyOne
File
- src/
OnlyOne.php, line 16
Namespace
Drupal\onlyoneView source
class OnlyOne implements OnlyOneInterface {
use StringTranslationTrait;
/**
* The entity type manager service.
*
* @var \Drupal\Core\Entity\EntityTypeManagerInterface
*/
protected $entityTypeManager;
/**
* The database connection.
*
* @var \Drupal\Core\Database\Connection
*/
protected $connection;
/**
* The language manager service.
*
* @var \Drupal\Core\Language\LanguageManagerInterface
*/
protected $languageManager;
/**
* The config factory.
*
* @var \Drupal\Core\Config\ConfigFactoryInterface
*/
protected $configFactory;
/**
* The onlyone service.
*
* @var \Drupal\onlyone\OnlyOnePrintStrategyInterface
*/
protected $formatter;
/**
* Constructor.
*
* @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
* The entity type manager.
* @param \Drupal\Core\Database\Connection $connection
* The database connection.
* @param \Drupal\Core\Language\LanguageManagerInterface $language_manager
* The language manager.
* @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
* The config factory.
* @param \Drupal\Core\StringTranslation\TranslationInterface $string_translation
* The string translation service.
*/
public function __construct(EntityTypeManagerInterface $entity_type_manager, Connection $connection, LanguageManagerInterface $language_manager, ConfigFactoryInterface $config_factory, TranslationInterface $string_translation) {
$this->entityTypeManager = $entity_type_manager;
$this->connection = $connection;
$this->languageManager = $language_manager;
$this->configFactory = $config_factory;
$this->stringTranslation = $string_translation;
$this->formatter = new OnlyOnePrintAdminPage();
}
/**
* Returns the temporary table name created with all the content types names.
*
* @return string
* The temporary table name.
*/
private function getTemporaryContentTypesTableName() {
// Looking for all the content types, as the content types are only
// accesibles through the entity_type.manager service we can't use a
// LEFT JOIN in only one query as is posible in Drupal 7
// (See Drupal 7 module version).
// @see https://drupal.stackexchange.com/q/233214/28275
// @see https://drupal.stackexchange.com/q/235640/28275
// Looking for the content type names from the config table.
$query_content_types = "SELECT DISTINCT SUBSTR(name, 11) AS type\n FROM {config}\n WHERE name LIKE 'node.type.%'";
// Creating a temporary table and returning the name.
return $this->connection
->queryTemporary($query_content_types);
}
/**
* {@inheritdoc}
*/
public function getContentTypesList() {
// Looking for all the content types, as the content types are only
// accesibles through the entity_type.manager service we can't use a
// LEFT JOIN in only one query as is posible in Drupal 7
// (See Drupal 7 module version).
// @see http://drupal.stackexchange.com/q/233214/28275
$content_types = $this->entityTypeManager
->getStorage('node_type')
->loadMultiple();
// Creating an array with all content types.
$content_types_list_label = [];
foreach ($content_types as $content_type) {
$content_types_list_label[$content_type
->id()] = $content_type
->label();
}
return $content_types_list_label;
}
/**
* {@inheritdoc}
*/
public function existsNodesContentType($content_type, $language = NULL) {
// Getting the entity query instance.
$query = $this->entityTypeManager
->getStorage('node')
->getQuery();
$query
->condition('type', $content_type);
// The site is multilingual?
if ($this->languageManager
->isMultilingual()) {
if (empty($language)) {
$language = $this->languageManager
->getCurrentLanguage()
->getId();
}
// Adding the language condition.
$query
->condition('langcode', $language);
}
$nids = $query
->execute();
// Extracting the nid from the array.
$nid = count($nids) ? array_pop($nids) : 0;
return $nid;
}
/**
* {@inheritdoc}
*/
public function deleteContentTypeConfig($content_type) {
// Getting the config file.
$config = $this->configFactory
->getEditable('onlyone.settings');
// Getting the content types configured to have onlyone node.
$onlyone_content_types = $config
->get('onlyone_node_types');
// Checking if the config exists.
$index = array_search($content_type, $onlyone_content_types);
if ($index !== FALSE) {
// Deleting the value from the array.
unset($onlyone_content_types[$index]);
// Saving the values in the config.
$config
->set('onlyone_node_types', $onlyone_content_types)
->save();
return TRUE;
}
return FALSE;
}
/**
* {@inheritdoc}
*/
public function getLanguageLabel($language) {
switch ($language) {
case LanguageInterface::LANGCODE_NOT_SPECIFIED:
case '':
// If the language is empty then is Not specified.
return $this->languageManager
->getLanguage(LanguageInterface::LANGCODE_NOT_SPECIFIED)
->getName();
case LanguageInterface::LANGCODE_NOT_APPLICABLE:
return $this->languageManager
->getLanguage(LanguageInterface::LANGCODE_NOT_APPLICABLE)
->getName();
default:
return ucfirst($language);
}
}
/**
* {@inheritdoc}
*/
public function getAvailableContentTypes() {
// Getting the temporary table with all the content type names.
$content_types_temporary_table_name = $this
->getTemporaryContentTypesTableName();
// Multilingual site?
if ($this->languageManager
->isMultilingual()) {
// Looking for content types that doesn't have more than 1 node
// in any language.
$query = "SELECT type\n FROM {$content_types_temporary_table_name}\n WHERE type NOT IN\n (SELECT node.type\n FROM {node} node\n JOIN {node_field_data} node_field_data USING(nid)\n GROUP BY type,\n node_field_data.langcode\n HAVING COUNT(nid) > 1)\n ORDER BY type ASC";
}
else {
// If the site is not multilingual we have only one language.
$query = "SELECT node_type.type\n FROM {$content_types_temporary_table_name} node_type\n LEFT JOIN {node} USING(type)\n GROUP BY type\n HAVING COUNT(nid) <= 1\n ORDER BY type ASC";
}
// Executing the query.
$result = $this->connection
->query($query);
// Getting the content types machine names.
$content_types = $result
->fetchCol();
return $content_types;
}
/**
* {@inheritdoc}
*/
public function getNotAvailableContentTypes() {
// Multilingual site?
if ($this->languageManager
->isMultilingual()) {
// Looking for content types with more than 1 node
// in at least one language.
$query = 'SELECT DISTINCT node.type
FROM {node} node
JOIN {node_field_data} node_field_data USING(nid)
GROUP BY type,
node_field_data.langcode
HAVING COUNT(nid) > 1
ORDER BY node.type ASC';
}
else {
// If the site is not multilingual we have only one language,
// and if we have a content type with more than one node,
// then it is not available for the Only One feature.
// Searching all the content types with nodes.
$query = "SELECT type\n FROM {node}\n GROUP BY type\n HAVING COUNT(nid) > 1\n ORDER BY type ASC";
}
// Executing the query.
$result = $this->connection
->query($query);
// Getting the content types machine names.
$content_types = $result
->fetchCol();
return $content_types;
}
/**
* {@inheritdoc}
*/
public function getAvailableContentTypesSummarized() {
// Getting the temporary table with all the content type names.
$content_types_temporary_table_name = $this
->getTemporaryContentTypesTableName();
// Multilingual site?
if ($this->languageManager
->isMultilingual()) {
// Looking for content types that doesn't have more than 1 node
// in any language.
$query = "SELECT DISTINCT node_type.type,\n node_field_data.langcode AS language,\n COUNT(node.nid) AS total\n FROM {$content_types_temporary_table_name} node_type\n LEFT JOIN {node} node USING(type)\n LEFT JOIN {node_field_data} node_field_data USING(nid)\n WHERE node_type.type NOT IN\n (SELECT node.type\n FROM {node} node\n JOIN {node_field_data} node_field_data USING(nid)\n GROUP BY type,\n node_field_data.langcode\n HAVING COUNT(nid) > 1)\n GROUP BY type,\n node_field_data.langcode\n ORDER BY node_type.type ASC";
}
else {
// If the site is not multilingual we have only one language.
$query = "SELECT type,\n COUNT(nid) AS total\n FROM {$content_types_temporary_table_name} node_type\n LEFT JOIN {node} USING(type)\n GROUP BY type\n HAVING COUNT(nid) <= 1\n ORDER BY type ASC";
}
// Executing the query.
$result = $this->connection
->query($query);
// Getting the information keyed by content type machine name.
$content_types = $result
->fetchAll(\PDO::FETCH_GROUP);
// Adding content type name and other information.
$this
->addAditionalInfoToContentTypes($content_types);
// Sorting by content type name (label).
uasort($content_types, function ($a, $b) {
return $a[0]->name <=> $b[0]->name;
});
return $content_types;
}
/**
* {@inheritdoc}
*/
public function getNotAvailableContentTypesSummarized() {
// Multilingual site?
if ($this->languageManager
->isMultilingual()) {
// Looking for content types that doesn't have more than 1 node
// in any language.
$query = "SELECT DISTINCT node.type,\n node_field_data.langcode AS language,\n COUNT(node.nid) AS total\n FROM {node} node\n JOIN {node_field_data} node_field_data USING(nid)\n WHERE node.type IN\n (SELECT DISTINCT node.type\n FROM {node} node\n JOIN {node_field_data} node_field_data USING(nid)\n GROUP BY type,\n node_field_data.langcode\n HAVING COUNT(nid) > 1)\n GROUP BY node.type,\n language\n ORDER BY node.type ASC";
}
else {
// If the site is not multilingual we have only one language.
$query = "SELECT type,\n COUNT(nid) AS total\n FROM {node}\n GROUP BY type\n HAVING COUNT(nid) > 1\n ORDER BY type ASC";
}
// Executing the query.
$result = $this->connection
->query($query);
// Getting the information keyed by content type machine name.
$content_types = $result
->fetchAll(\PDO::FETCH_GROUP);
// Adding content type name and other information.
$this
->addAditionalInfoToContentTypes($content_types);
return $content_types;
}
/**
* Add additional information to the content types.
*
* @param array $content_types
* The content types.
*/
private function addAditionalInfoToContentTypes(array &$content_types) {
// Getting the content types label list.
$content_types_list_label = $this
->getContentTypesList();
// Getting configured content types.
$configured_content_types = $this->configFactory
->get('onlyone.settings')
->get('onlyone_node_types');
// Iterating over all the content types.
foreach ($content_types as $conten_type => $content_type_info) {
// Getting the total of languages.
$cant = count($content_type_info);
// Iterating over each language.
for ($i = 0; $i < $cant; $i++) {
$content_types[$conten_type][$i]->configured = in_array($conten_type, $configured_content_types) ? TRUE : FALSE;
// Adding the content type name.
$content_types[$conten_type][$i]->name = $content_types_list_label[$conten_type];
// The format for multilingual is diferent from non multilingual sites.
if ($this->languageManager
->isMultilingual()) {
// Getting the language label.
$language = $this
->getLanguageLabel($content_type_info[$i]->language);
// Adding text with total nodes.
$total_nodes = $content_type_info[$i]->total ? $this
->formatPlural($content_type_info[$i]->total, '@language: @total Node', '@language: @total Nodes', [
'@language' => $language,
'@total' => $content_type_info[$i]->total,
]) : $this
->t('0 Nodes');
}
else {
// Adding text with total nodes.
$total_nodes = $content_type_info[$i]->total ? $this
->formatPlural($content_type_info[$i]->total, '@total Node', '@total Nodes', [
'@total' => $content_type_info[$i]->total,
]) : $this
->t('0 Nodes');
}
// Adding the total nodes information.
$content_types[$conten_type][$i]->total_nodes = $total_nodes;
}
}
}
/**
* {@inheritdoc}
*/
public function setFormatter(OnlyOnePrintStrategyInterface $formatter) {
$this->formatter = $formatter;
return $this;
}
/**
* {@inheritdoc}
*/
public function getAvailableContentTypesForPrint() {
return $this->formatter
->getContentTypesListForPrint($this
->getAvailableContentTypesSummarized());
}
/**
* {@inheritdoc}
*/
public function getNotAvailableContentTypesForPrint() {
return $this->formatter
->getContentTypesListForPrint($this
->getNotAvailableContentTypesSummarized());
}
}
Members
Name | Modifiers | Type | Description | Overrides |
---|---|---|---|---|
OnlyOne:: |
protected | property | The config factory. | |
OnlyOne:: |
protected | property | The database connection. | |
OnlyOne:: |
protected | property | The entity type manager service. | |
OnlyOne:: |
protected | property | The onlyone service. | |
OnlyOne:: |
protected | property | The language manager service. | |
OnlyOne:: |
private | function | Add additional information to the content types. | |
OnlyOne:: |
public | function |
Delete the content type config variable. Overrides OnlyOneInterface:: |
|
OnlyOne:: |
public | function |
Returns if exists nodes of a content type in the actual language. Overrides OnlyOneInterface:: |
|
OnlyOne:: |
public | function |
Return the available content types. Overrides OnlyOneInterface:: |
|
OnlyOne:: |
public | function |
Return a list of available content types for print. Overrides OnlyOneInterface:: |
|
OnlyOne:: |
public | function |
Return the available content types with their number of nodes. Overrides OnlyOneInterface:: |
|
OnlyOne:: |
public | function |
Returns a content type label list. Overrides OnlyOneInterface:: |
|
OnlyOne:: |
public | function |
Returns the language label. Overrides OnlyOneInterface:: |
|
OnlyOne:: |
public | function |
Return the not available content types. Overrides OnlyOneInterface:: |
|
OnlyOne:: |
public | function |
Return a list of non-available content types for print. Overrides OnlyOneInterface:: |
|
OnlyOne:: |
public | function |
Return the not available content types with their number of nodes. Overrides OnlyOneInterface:: |
|
OnlyOne:: |
private | function | Returns the temporary table name created with all the content types names. | |
OnlyOne:: |
public | function |
Set the formatter for printing. Overrides OnlyOneInterface:: |
|
OnlyOne:: |
public | function | Constructor. | |
StringTranslationTrait:: |
protected | property | The string translation service. | 1 |
StringTranslationTrait:: |
protected | function | Formats a string containing a count of items. | |
StringTranslationTrait:: |
protected | function | Returns the number of plurals supported by a given language. | |
StringTranslationTrait:: |
protected | function | Gets the string translation service. | |
StringTranslationTrait:: |
public | function | Sets the string translation service to use. | 2 |
StringTranslationTrait:: |
protected | function | Translates a string to the current language or to a given language. |