createcontentwithcategory-1.0.0-alpha1/src/Ccwc.php
src/Ccwc.php
<?php
namespace Drupal\createcontentwithcategory;
use Drupal\core\Url;
use Drupal\Core\Template\Attribute;
/**
* Encapsulates useful methods for creating content with category.
*/
class Ccwc { // implements CcwcInterface {
/**
* The identification string for this create content with category object.
*
* @var string
*/
public $id;
/**
* The content (node) type machine name.
*
* @var string
*/
public $content_type;
/**
* The field machine name.
*
* @var string
*/
public $field_name;
public function __construct($id) {
$this->id = $id;
$parts = explode('__', $id);
if (count($parts) !== 2) {
throw new \Exception("Invalid Create Content with Category ID: $id");
}
$this->content_type = $parts[0];
$this->field_name = $parts[1];
}
public function label() {
return t("Create :content_type content with category :field", [':field' => $this->fieldLabel(), ':content_type' => $this->contentTypeLabel()]);
}
public function permission() {
return 'create ' . $this->content_type;
}
public function fieldLabel() {
return $this->getField()->label();
}
public function getField() {
$entity_type = 'node';
$bundle = $this->content_type;
$field_name = $this->field_name;
return \Drupal\field\Entity\FieldConfig::loadByName($entity_type, $bundle, $field_name);
}
public function contentTypeLabel() {
return \Drupal::entityTypeManager()
->getStorage('node_type')
->load($this->content_type)
->label();
}
public function build() {
$build = [];
$items = $this->buildItems();
if ($items) {
// Make sure drupal_render() does not re-order the links.
$build['#sorted'] = TRUE;
// Make up a menu name.
$menu_name = $this->id;
// Add the theme wrapper for outer markup.
// Allow menu-specific theme overrides.
$build['#theme'] = 'menu__' . strtr($menu_name, '-', '_');
$build['#menu_name'] = $menu_name;
$build['#items'] = $items;
// Set cache tag. - this should refresh when the vocabulary terms change, if we have a way to get that in Drupal. Skipping for now.
// $build['#cache']['tags'][] = 'config:system.menu.' . $menu_name;
}
return $build;
}
public function buildItems() {
$items = [];
$terms = $this->getTerms();
foreach ($terms as $id => $term) {
$element = [];
$element['attributes'] = new Attribute();
$element['title'] = $term->getName();
$element['original_term'] = $term;
$element['url'] = $this->makeUrl($id);
$items[$id] = $element;
}
return $items;
}
public function getTerms() {
$terms = [];
$field = $this->getField();
$vocab_names = $field->getSettings()['handler_settings']['target_bundles'];
foreach ($vocab_names as $vocab_name) {
// Preserve numeric keys (why not!) and do the merge in one line, nice.
$terms += \Drupal::entityTypeManager()->getStorage('taxonomy_term') ->loadByProperties(['vid' => $vocab_name]);
}
return $terms;
}
public function makeUrl($term_id) {
return Url::fromRoute('node.add', [
'node_type' => $this->content_type,
], [
'query' => [
$this->prepopulateQueryKey() => $term_id,
],
]);
}
public function prepopulateQueryKey() {
// The documented approach does not work for select lists
// "edit[$this->field_name][widget][0][target_id]"
// Below does work for select lists, though it's not documented.
// @TODO look up what kind of field we have and produce a working
// prepopulate link based on trial and error and the 'documentation'
// https://git.drupalcode.org/project/prepopulate/blob/8.x-2.x/tests/src/Functional/PrepopulateFieldTest.php
// Again note that what we do here is not in the tests nor documentation.
return "edit[$this->field_name][widget]";
}
}
