onlyone-8.x-1.x-dev/src/OnlyOne.php
src/OnlyOne.php
<?php
namespace Drupal\onlyone;
use Drupal\Core\Config\ConfigFactoryInterface;
use Drupal\Core\Database\Connection;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Language\LanguageInterface;
use Drupal\Core\Language\LanguageManagerInterface;
use Drupal\Core\StringTranslation\StringTranslationTrait;
use Drupal\Core\StringTranslation\TranslationInterface;
/**
* Defines the OnlyOne class.
*
* Implements functionality related to managing content
* types for the Only One module.
*/
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
FROM {config}
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);
}
$query->accessCheck(FALSE);
$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
FROM $content_types_temporary_table_name
WHERE type NOT IN
(SELECT 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 type ASC";
}
else {
// If the site is not multilingual we have only one language.
$query = "SELECT node_type.type
FROM $content_types_temporary_table_name node_type
LEFT JOIN {node} USING(type)
GROUP BY type
HAVING COUNT(nid) <= 1
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
FROM {node}
GROUP BY type
HAVING COUNT(nid) > 1
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,
node_field_data.langcode AS language,
COUNT(node.nid) AS total
FROM $content_types_temporary_table_name node_type
LEFT JOIN {node} node USING(type)
LEFT JOIN {node_field_data} node_field_data USING(nid)
WHERE node_type.type NOT IN
(SELECT 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)
GROUP BY type,
node_field_data.langcode
ORDER BY node_type.type ASC";
}
else {
// If the site is not multilingual we have only one language.
$query = "SELECT type,
COUNT(nid) AS total
FROM $content_types_temporary_table_name node_type
LEFT JOIN {node} USING(type)
GROUP BY type
HAVING COUNT(nid) <= 1
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,
node_field_data.langcode AS language,
COUNT(node.nid) AS total
FROM {node} node
JOIN {node_field_data} node_field_data USING(nid)
WHERE node.type IN
(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)
GROUP BY node.type,
language
ORDER BY node.type ASC";
}
else {
// If the site is not multilingual we have only one language.
$query = "SELECT type,
COUNT(nid) AS total
FROM {node}
GROUP BY type
HAVING COUNT(nid) > 1
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());
}
}
