Skip to content

API Documentation

This guide provides technical documentation for developers working with the Knowledge module. It covers the module's API, services, plugins, hooks, and integration points.

Table of Contents

Architecture Overview

Entity Structure

The Knowledge module provides four main content entities:

knowledge (Content Entity)
├── Knowledge entity links incidents to content
├── Revisioable, publishable, ownable
└── Bundles: Knowledge Types (Config Entity)

knowledge_competency (Content Entity)
├── Tracks user competency across roles
├── Revisionable with editorial workflow
└── No bundles

knowledge_adherence (Content Entity)
├── Tracks adherence to knowledge linking practices
├── Not revisionable
└── No bundles

knowledge_quality (Content Entity)
├── Quality assessment of knowledge articles
├── Revisionable with editorial workflow
└── No bundles

Service Architecture

knowledge.manager
├── Core knowledge management functionality
├── Entity creation and manipulation
└── Statistics aggregation

knowledge.statistics
├── Statistical calculations
├── Frequency tracking (short/medium/long)
└── Citation vs. direct knowledge tracking

knowledge.competency
├── Competency calculation
├── Role progression logic
└── Proposal and approval workflows

knowledge.leader
├── Leader assignment
└── Coach/learner relationships

knowledge.link_builder
├── Generates knowledge link render arrays
└── Permission checking

Entities

Knowledge Entity

Entity Type ID: knowledge
Class: Drupal\knowledge\Entity\Knowledge
Interface: Drupal\knowledge\KnowledgeInterface

Base Fields

// Entity identification
$fields['kid']           // Knowledge ID (primary key)
$fields['uuid']          // Universally unique identifier
$fields['knowledge_type'] // Bundle (knowledge type)
$fields['revision_id']   // Revision ID

// Ownership and status
$fields['uid']           // Author user ID
$fields['status']        // Published status (0/1)
$fields['created']       // Creation timestamp
$fields['changed']       // Last modification timestamp

// Linking information
$fields['field_name']    // Field name through which knowledge was added
$fields['entity_type']   // Target entity type
$fields['entity_id']     // Target entity ID
$fields['entity_revision'] // Target entity revision
$fields['incident_type'] // Incident entity type
$fields['incident_id']   // Incident entity ID

// Classification
$fields['citation']      // Is this a citation? (boolean)

Key Methods

// Get linked entities
$knowledge->getKnowledgeedEntity();      // Returns target entity
$knowledge->getKnowledgeedEntityId();    // Returns target entity ID
$knowledge->getKnowledgeedEntityTypeId(); // Returns target entity type

// Get incident entities
$knowledge->getIncidentEntity();         // Returns incident entity
$knowledge->getIncidentEntityId();       // Returns incident ID
$knowledge->getIncidentEntityTypeId();   // Returns incident type

// Field operations
$knowledge->getFieldName();              // Returns field name
$knowledge->setFieldName($field_name);   // Sets field name

// Metadata
$knowledge->getAuthorName();             // Returns author display name
$knowledge->getCreatedTime();            // Returns creation timestamp
$knowledge->permalink();                 // Returns URL with fragment

Creating Knowledge Programmatically

use Drupal\knowledge\Entity\Knowledge;

$knowledge = Knowledge::create([
  'knowledge_type' => 'support_to_article',
  'uid' => \Drupal::currentUser()->id(),
  'status' => 1,
  'field_name' => 'field_knowledge',
  'entity_type' => 'node',
  'entity_id' => $article_nid,
  'incident_type' => 'node',
  'incident_id' => $ticket_nid,
]);
$knowledge->save();

Querying Knowledge

$query = \Drupal::entityTypeManager()
  ->getStorage('knowledge')
  ->getQuery()
  ->accessCheck(TRUE);

// Filter by knowledge type
$query->condition('knowledge_type', 'support_to_article');

// Filter by target entity
$query->condition('entity_type', 'node');
$query->condition('entity_id', $nid);

// Filter by incident
$query->condition('incident_type', 'node');
$query->condition('incident_id', $ticket_id);

// Filter by author
$query->condition('uid', $uid);

// Filter by date range
$query->condition('created', strtotime('-30 days'), '>=');

// Filter by citation status
$query->condition('citation', 0); // Direct knowledge only

$knowledge_ids = $query->execute();
$knowledge_entities = Knowledge::loadMultiple($knowledge_ids);

Knowledge Type Entity

Entity Type ID: knowledge_type
Class: Drupal\knowledge\Entity\KnowledgeType
Interface: Drupal\knowledge\KnowledgeTypeInterface

Configuration

use Drupal\knowledge\Entity\KnowledgeType;

$knowledge_type = KnowledgeType::create([
  'id' => 'support_to_article',
  'label' => 'Support Ticket to Article',
  'description' => 'Links support tickets to knowledge base articles.',
  'target_entity_type_id' => 'node',
  'incident_entity_type_id' => 'node',
]);
$knowledge_type->save();

Key Methods

$knowledge_type->getTargetEntityTypeId();   // Returns target entity type
$knowledge_type->getIncidentEntityTypeId(); // Returns incident entity type
$knowledge_type->getDescription();          // Returns description

Knowledge Competency Entity

Entity Type ID: knowledge_competency
Class: Drupal\knowledge\Entity\Competency
Interface: Drupal\knowledge\KnowledgeCompetencyInterface

Base Fields

$fields['id']         // Competency ID
$fields['user_id']    // Learner user ID
$fields['roles']      // Multi-value competency role field
$fields['correct']    // Total correct competencies
$fields['total']      // Total competencies required
$fields['completed']  // Completion timestamp
$fields['created']    // Creation timestamp
$fields['changed']    // Modification timestamp

// Legacy role fields (auto-populated from roles)
$fields['candidate_correct']
$fields['candidate_total']
$fields['contributor_correct']
$fields['contributor_total']
$fields['contributor_proposed']
$fields['contributor_approved']
$fields['contributor_coach']
$fields['contributor_leader']
$fields['publisher_correct']
$fields['publisher_total']
$fields['publisher_proposed']
$fields['publisher_approved']
$fields['publisher_coach']
$fields['publisher_leader']

Working with Competencies

use Drupal\knowledge\Entity\Competency;

// Load user's competency
$competency = \Drupal::entityTypeManager()
  ->getStorage('knowledge_competency')
  ->loadByProperties(['user_id' => $uid]);

if (!empty($competency)) {
  $competency = reset($competency);

  // Get overall progress
  $correct = $competency->get('correct')->value;
  $total = $competency->get('total')->value;
  $percentage = ($total > 0) ? ($correct / $total) * 100 : 0;

  // Check for pending proposals
  $pending_role = $competency->isPending();
  if ($pending_role) {
    // User has pending proposal for advancement
  }

  // Check completion
  if ($competency->get('completed')->value) {
    $completed_time = $competency->get('completed')->value;
    // All competencies achieved
  }
}

Knowledge Adherence Entity

Entity Type ID: knowledge_adherence
Class: Drupal\knowledge\Entity\KnowledgeAdherence

Base Fields

$fields['id']            // Adherence ID
$fields['name']          // Label/description
$fields['uid']           // Creator user ID
$fields['learner']       // Learner being evaluated
$fields['incident_id']   // Incident entity reference
$fields['incident_type'] // Incident entity type
$fields['knowledge_id']  // Knowledge entity reference
$fields['article_id']    // Article entity reference
$fields['article_type']  // Article type
$fields['linked']        // Was article linked? (nullable boolean)
$fields['reused']        // Created or reused? (nullable boolean)
$fields['accurate']      // Was article accurate? (nullable boolean)
$fields['improve']       // Needs improvement? (nullable boolean)
$fields['required']      // Was article required? (nullable boolean)
$fields['found']         // Could find article? (nullable boolean)
$fields['disposition']   // Incident disposition
$fields['created']       // Creation timestamp
$fields['changed']       // Modification timestamp

Knowledge Quality Entity

Entity Type ID: knowledge_quality
Class: Drupal\knowledge\Entity\KnowledgeQuality

Base Fields

$fields['id']         // Quality ID
$fields['user_id']    // Reviewer user ID
$fields['entity_type'] // Reviewed entity type
$fields['entity_id']   // Reviewed entity ID
$fields['entity_vid']  // Reviewed entity revision
$fields['correct']     // Criteria marked as correct
$fields['total']       // Total criteria
$fields['status']      // Published status
$fields['created']     // Review timestamp
$fields['changed']     // Modification timestamp

Key Methods

$quality->getTotal();    // Returns total criteria count
$quality->getCorrect();  // Returns correct criteria count
$quality->getScore();    // Returns calculated quality score

Calculating Quality Scores

use Drupal\knowledge\Entity\KnowledgeQuality;

// Score formula: 100 * ((correct - incorrect) / total)
$score = $quality->getScore();

// Score ranges:
// 90-100: Excellent
// 70-89:  Good
// 50-69:  Fair
// <50:    Poor

Services

knowledge.manager

Class: Drupal\knowledge\KnowledgeManager
Service ID: knowledge.manager

Main service for knowledge management operations.

$knowledge_manager = \Drupal::service('knowledge.manager');

Methods

// Get knowledge field for an entity
$knowledge_manager->getFields($entity_type_id);

// Get display mode for knowledge field
$knowledge_manager->getDisplayMode($entity_type_id, $bundle);

// Check if knowledge is enabled for entity
$knowledge_manager->isEnabled($entity);

// Get knowledge form
$knowledge_manager->getForm($entity);

knowledge.statistics

Class: Drupal\knowledge\KnowledgeStatistics
Service ID: knowledge.statistics

Handles knowledge statistics calculation and tracking.

$statistics = \Drupal::service('knowledge.statistics');

Methods

// Update statistics for a knowledge entity
$statistics->update($knowledge);

// Get statistics for an entity
$stats = $statistics->read($entity_id, $entity_type);
// Returns array:
// - total_count: Total knowledge links
// - short_count: Links in short period
// - medium_count: Links in medium period
// - long_count: Links in long period
// - total_citation: Total citations
// - short_citation: Citations in short period
// - medium_citation: Citations in medium period
// - long_citation: Citations in long period

// Delete statistics for an entity
$statistics->delete($entity_id, $entity_type);

// Get top knowledge entities
$top = $statistics->getTopKnowledge($limit = 10);

knowledge.competency

Class: Drupal\knowledge\Service\CompetencyService
Service ID: knowledge.competency

Manages competency calculations and workflows.

$competency_service = \Drupal::service('knowledge.competency');

Methods

// Calculate competencies for a user
$competency_service->calculate($user);

// Propose user for role advancement
$competency_service->propose($competency, $role);

// Approve role advancement
$competency_service->approve($competency, $role);

// Pre-save operations
$competency_service->doPreSave($roles, $original_roles);

// Post-save operations
$competency_service->doPostSave($user, $roles, $original_roles);

knowledge.leader

Class: Drupal\knowledge\Service\KnowledgeLeaderService
Service ID: knowledge.leader

Manages leader and coach assignments.

$leader_service = \Drupal::service('knowledge.leader');

Methods

// Get user's leader
$leader = $leader_service->getLeader($user);

// Get user's coach
$coach = $leader_service->getCoach($user);

// Get all users for a leader
$followers = $leader_service->getFollowers($leader);

// Get all users for a coach
$learners = $leader_service->getLearners($coach);

Hooks

Alter knowledge link render arrays before display.

/**
 * Implements hook_knowledge_links_alter().
 */
function mymodule_knowledge_links_alter(array &$links, KnowledgeInterface $entity, array &$context) {
  // Add custom link
  $links['mymodule'] = [
    '#theme' => 'links__knowledge__mymodule',
    '#attributes' => ['class' => ['links', 'inline']],
    '#links' => [
      'knowledge-report' => [
        'title' => t('Report Issue'),
        'url' => Url::fromRoute('mymodule.report', [
          'knowledge' => $entity->id()
        ]),
      ],
    ],
  ];

  // Modify existing links
  if (isset($links['knowledge']['#links']['knowledge-delete'])) {
    // Change delete link text
    $links['knowledge']['#links']['knowledge-delete']['title'] = t('Remove');
  }

  // Remove links based on context
  if ($context['view_mode'] == 'teaser') {
    unset($links['knowledge']['#links']['knowledge-edit']);
  }
}

Entity Hooks

Standard Drupal entity hooks work with knowledge entities:

/**
 * Implements hook_knowledge_presave().
 */
function mymodule_knowledge_presave(EntityInterface $entity) {
  // Act before knowledge entity is saved
  if ($entity->bundle() == 'support_to_article') {
    // Custom logic for specific knowledge type
  }
}

/**
 * Implements hook_knowledge_insert().
 */
function mymodule_knowledge_insert(EntityInterface $entity) {
  // Act after new knowledge entity is created
  \Drupal::logger('mymodule')->notice('Knowledge @id created', [
    '@id' => $entity->id(),
  ]);
}

/**
 * Implements hook_knowledge_update().
 */
function mymodule_knowledge_update(EntityInterface $entity) {
  // Act after knowledge entity is updated
}

/**
 * Implements hook_knowledge_delete().
 */
function mymodule_knowledge_delete(EntityInterface $entity) {
  // Act after knowledge entity is deleted
  // Clean up custom data
}

Plugins

Field Type: Knowledge

Plugin ID: knowledge
Class: Drupal\knowledge\Plugin\Field\FieldType\KnowledgeItem

Storage Settings

[
  'knowledge_type' => 'support_to_article', // Knowledge type ID
  'short_period' => 15,    // Days for short frequency
  'medium_period' => 90,   // Days for medium frequency
  'long_period' => 365,    // Days for long frequency
]

Field Settings

[
  'per_page' => 50,              // Links per page
  'anonymous' => 0,              // Anonymous linking permission
  'form_location' => 1,          // Form display location
]

Field Type: Knowledge Competency Role

Plugin ID: knowledge_competency_role
Class: Drupal\knowledge_field\Plugin\Field\FieldType\KnowledgeCompetencyRoleItem

Multi-value field tracking competency per role.

Properties

[
  'role' => 'knowledge_contributor',  // Role machine name
  'correct' => 5,                     // Correct competencies
  'total' => 10,                      // Total competencies
  'proposed' => 1234567890,           // Proposed timestamp
  'approved' => 1234567891,           // Approved timestamp
  'proposer' => 3,                    // Proposer user ID
  'approver' => 2,                    // Approver user ID
]

Migrate Destination Plugins

EntityKnowledge

Migrate destination for knowledge entities.

id: my_knowledge_migration
migration_tags:
  - Knowledge
source:
  plugin: csv
  path: 'path/to/knowledge.csv'
  ids:
    - id
process:
  knowledge_type: 'support_to_article'
  uid:
    plugin: migration_lookup
    migration: user_migration
    source: user_id
  entity_type: 'node'
  entity_id:
    plugin: migration_lookup
    migration: article_migration
    source: article_id
  incident_type: 'node'
  incident_id:
    plugin: migration_lookup
    migration: ticket_migration
    source: ticket_id
  field_name: 'field_knowledge'
  status: 1
destination:
  plugin: entity:knowledge

EntityKnowledgeType

Migrate destination for knowledge types.

id: knowledge_type_migration
source:
  plugin: csv
  path: 'path/to/knowledge_types.csv'
process:
  id: machine_name
  label: label
  description: description
  target_entity_type_id: target_entity_type
  incident_entity_type_id: incident_entity_type
destination:
  plugin: entity:knowledge_type

Field Types

Creating a Custom Knowledge Field Widget

namespace Drupal\mymodule\Plugin\Field\FieldWidget;

use Drupal\Core\Field\FieldItemListInterface;
use Drupal\Core\Field\WidgetBase;
use Drupal\Core\Form\FormStateInterface;

/**
 * Plugin implementation of custom knowledge widget.
 *
 * @FieldWidget(
 *   id = "mymodule_knowledge_custom",
 *   label = @Translation("Custom Knowledge Widget"),
 *   field_types = {
 *     "knowledge"
 *   }
 * )
 */
class CustomKnowledgeWidget extends WidgetBase {

  /**
   * {@inheritdoc}
   */
  public function formElement(FieldItemListInterface $items, $delta, array $element, array &$form, FormStateInterface $form_state) {
    $element['status'] = [
      '#type' => 'select',
      '#title' => $this->t('Knowledge Status'),
      '#options' => [
        0 => $this->t('Disabled'),
        1 => $this->t('Read only'),
        2 => $this->t('Read/Write'),
      ],
      '#default_value' => $items[$delta]->status ?? 2,
    ];

    // Add custom elements
    $element['custom_field'] = [
      '#type' => 'textfield',
      '#title' => $this->t('Custom Field'),
    ];

    return $element;
  }

}

Creating a Custom Knowledge Field Formatter

namespace Drupal\mymodule\Plugin\Field\FieldFormatter;

use Drupal\Core\Field\FieldItemListInterface;
use Drupal\Core\Field\FormatterBase;

/**
 * Plugin implementation of custom knowledge formatter.
 *
 * @FieldFormatter(
 *   id = "mymodule_knowledge_custom",
 *   label = @Translation("Custom Knowledge Formatter"),
 *   field_types = {
 *     "knowledge"
 *   }
 * )
 */
class CustomKnowledgeFormatter extends FormatterBase {

  /**
   * {@inheritdoc}
   */
  public function viewElements(FieldItemListInterface $items, $langcode) {
    $elements = [];

    foreach ($items as $delta => $item) {
      $elements[$delta] = [
        '#markup' => $this->t('Knowledge status: @status', [
          '@status' => $item->status,
        ]),
      ];
    }

    return $elements;
  }

}

Storage and Schema

Database Tables

knowledge

Main knowledge entity table.

CREATE TABLE `knowledge` (
  `kid` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
  `uuid` VARCHAR(128) NOT NULL,
  `revision_id` INT(10) UNSIGNED,
  `knowledge_type` VARCHAR(32) NOT NULL,
  `uid` INT(10) UNSIGNED NOT NULL,
  `field_name` VARCHAR(32) NOT NULL,
  `entity_type` VARCHAR(32) NOT NULL,
  `entity_id` INT(10) UNSIGNED NOT NULL,
  `entity_revision` INT(10) UNSIGNED,
  `incident_type` VARCHAR(32) NOT NULL,
  `incident_id` INT(10) UNSIGNED NOT NULL,
  `citation` TINYINT(4) NOT NULL DEFAULT 0,
  `status` TINYINT(4) NOT NULL DEFAULT 1,
  `created` INT(11) NOT NULL DEFAULT 0,
  `changed` INT(11) NOT NULL DEFAULT 0,
  PRIMARY KEY (`kid`),
  KEY `entity` (`entity_type`, `entity_id`),
  KEY `incident` (`incident_type`, `incident_id`),
  KEY `user` (`uid`),
  KEY `created` (`created`)
);

knowledge_entity_statistics

Statistics aggregation table.

CREATE TABLE `knowledge_entity_statistics` (
  `entity_id` INT(10) UNSIGNED NOT NULL,
  `entity_type` VARCHAR(32) NOT NULL,
  `field_name` VARCHAR(32) NOT NULL,
  `total_count` BIGINT(20) UNSIGNED NOT NULL DEFAULT 0,
  `short_count` BIGINT(20) UNSIGNED NOT NULL DEFAULT 0,
  `medium_count` BIGINT(20) UNSIGNED NOT NULL DEFAULT 0,
  `long_count` BIGINT(20) UNSIGNED NOT NULL DEFAULT 0,
  `total_citation` BIGINT(20) UNSIGNED NOT NULL DEFAULT 0,
  `short_citation` BIGINT(20) UNSIGNED NOT NULL DEFAULT 0,
  `medium_citation` BIGINT(20) UNSIGNED NOT NULL DEFAULT 0,
  `long_citation` BIGINT(20) UNSIGNED NOT NULL DEFAULT 0,
  `last_knowledge_timestamp` INT(11),
  `last_knowledge_uid` INT(10) UNSIGNED,
  PRIMARY KEY (`entity_id`, `entity_type`, `field_name`)
);

Custom Schema Definitions

/**
 * Implements hook_schema().
 */
function mymodule_schema() {
  $schema['mymodule_knowledge_tracking'] = [
    'description' => 'Tracks custom knowledge metrics',
    'fields' => [
      'id' => [
        'type' => 'serial',
        'not null' => TRUE,
      ],
      'kid' => [
        'type' => 'int',
        'unsigned' => TRUE,
        'not null' => TRUE,
      ],
      'metric_name' => [
        'type' => 'varchar',
        'length' => 255,
        'not null' => TRUE,
      ],
      'metric_value' => [
        'type' => 'float',
        'not null' => TRUE,
      ],
      'timestamp' => [
        'type' => 'int',
        'not null' => TRUE,
        'default' => 0,
      ],
    ],
    'primary key' => ['id'],
    'indexes' => [
      'kid' => ['kid'],
      'timestamp' => ['timestamp'],
    ],
    'foreign keys' => [
      'knowledge' => [
        'table' => 'knowledge',
        'columns' => ['kid' => 'kid'],
      ],
    ],
  ];

  return $schema;
}

Migration Support

Migrating from Legacy System

Example migration from legacy knowledge system:

id: legacy_knowledge
label: Legacy Knowledge Migration
migration_group: knowledge
source:
  plugin: legacy_knowledge_source
  # Custom source plugin
process:
  # Map knowledge type
  knowledge_type:
    plugin: static_map
    source: type
    map:
      1: 'support_to_article'
      2: 'issue_to_solution'
    default_value: 'support_to_article'

  # Map user
  uid:
    plugin: migration_lookup
    migration: users
    source: user_id
    no_stub: true

  # Map entities
  entity_type:
    plugin: static_map
    source: target_type
    map:
      article: 'node'
      page: 'node'

  entity_id:
    plugin: migration_lookup
    migration: content
    source: target_id
    no_stub: true

  incident_type:
    plugin: default_value
    default_value: 'node'

  incident_id:
    plugin: migration_lookup
    migration: tickets
    source: ticket_id
    no_stub: true

  field_name:
    plugin: default_value
    default_value: 'field_knowledge'

  # Map status
  status:
    plugin: static_map
    source: published
    map:
      0: 0
      1: 1
    default_value: 1

  # Map timestamps
  created: created_date
  changed: modified_date

destination:
  plugin: entity:knowledge

migration_dependencies:
  required:
    - users
    - content
    - tickets

Custom Source Plugin

namespace Drupal\mymodule\Plugin\migrate\source;

use Drupal\migrate\Plugin\migrate\source\SqlBase;

/**
 * Source plugin for legacy knowledge data.
 *
 * @MigrateSource(
 *   id = "legacy_knowledge_source"
 * )
 */
class LegacyKnowledgeSource extends SqlBase {

  /**
   * {@inheritdoc}
   */
  public function query() {
    $query = $this->select('legacy_knowledge', 'lk')
      ->fields('lk', [
        'id',
        'type',
        'user_id',
        'target_type',
        'target_id',
        'ticket_id',
        'published',
        'created_date',
        'modified_date',
      ]);
    return $query;
  }

  /**
   * {@inheritdoc}
   */
  public function fields() {
    return [
      'id' => $this->t('Knowledge ID'),
      'type' => $this->t('Knowledge Type'),
      'user_id' => $this->t('User ID'),
      'target_type' => $this->t('Target Type'),
      'target_id' => $this->t('Target ID'),
      'ticket_id' => $this->t('Ticket ID'),
      'published' => $this->t('Published Status'),
      'created_date' => $this->t('Created Date'),
      'modified_date' => $this->t('Modified Date'),
    ];
  }

  /**
   * {@inheritdoc}
   */
  public function getIds() {
    return [
      'id' => [
        'type' => 'integer',
        'alias' => 'lk',
      ],
    ];
  }

}

Testing

Kernel Tests

namespace Drupal\Tests\knowledge\Kernel;

use Drupal\KernelTests\KernelTestBase;
use Drupal\knowledge\Entity\Knowledge;
use Drupal\knowledge\Entity\KnowledgeType;

/**
 * Tests Knowledge entity functionality.
 *
 * @group knowledge
 */
class KnowledgeEntityTest extends KernelTestBase {

  /**
   * {@inheritdoc}
   */
  protected static $modules = [
    'knowledge',
    'knowledge_field',
    'node',
    'field',
    'text',
    'user',
    'system',
  ];

  /**
   * {@inheritdoc}
   */
  protected function setUp(): void {
    parent::setUp();

    $this->installEntitySchema('user');
    $this->installEntitySchema('node');
    $this->installEntitySchema('knowledge');
    $this->installEntitySchema('knowledge_type');
    $this->installConfig(['knowledge', 'node']);
  }

  /**
   * Tests knowledge entity creation.
   */
  public function testKnowledgeCreation() {
    // Create knowledge type
    $knowledge_type = KnowledgeType::create([
      'id' => 'test_type',
      'label' => 'Test Type',
      'target_entity_type_id' => 'node',
      'incident_entity_type_id' => 'node',
    ]);
    $knowledge_type->save();

    // Create knowledge
    $knowledge = Knowledge::create([
      'knowledge_type' => 'test_type',
      'uid' => 1,
      'entity_type' => 'node',
      'entity_id' => 1,
      'incident_type' => 'node',
      'incident_id' => 2,
      'field_name' => 'field_knowledge',
    ]);
    $knowledge->save();

    // Assert
    $this->assertNotNull($knowledge->id());
    $this->assertEquals('test_type', $knowledge->bundle());
    $this->assertEquals('node', $knowledge->getKnowledgeedEntityTypeId());
  }

}

Functional Tests

namespace Drupal\Tests\knowledge\Functional;

use Drupal\Tests\BrowserTestBase;

/**
 * Tests knowledge UI functionality.
 *
 * @group knowledge
 */
class KnowledgeUiTest extends BrowserTestBase {

  /**
   * {@inheritdoc}
   */
  protected static $modules = ['knowledge', 'node'];

  /**
   * {@inheritdoc}
   */
  protected $defaultTheme = 'stark';

  /**
   * Tests knowledge type creation through UI.
   */
  public function testKnowledgeTypeCreation() {
    // Create admin user
    $admin = $this->drupalCreateUser([
      'administer knowledge types',
    ]);
    $this->drupalLogin($admin);

    // Visit knowledge type creation page
    $this->drupalGet('admin/structure/knowledge/link/types/add');
    $this->assertSession()->statusCodeEquals(200);

    // Fill in form
    $edit = [
      'label' => 'Test Knowledge Type',
      'id' => 'test_knowledge_type',
      'description' => 'Test description',
      'target_entity_type_id' => 'node',
      'incident_entity_type_id' => 'node',
    ];
    $this->submitForm($edit, 'Save');

    // Assert success
    $this->assertSession()->pageTextContains('Saved the Test Knowledge Type knowledge type');
  }

}

Extending the Module

Creating a Custom Knowledge Statistics Calculator

namespace Drupal\mymodule\Service;

use Drupal\knowledge\KnowledgeInterface;
use Drupal\knowledge\KnowledgeStatistics;

/**
 * Custom knowledge statistics calculator.
 */
class CustomKnowledgeStatistics extends KnowledgeStatistics {

  /**
   * {@inheritdoc}
   */
  public function update(KnowledgeInterface $knowledge) {
    // Call parent implementation
    parent::update($knowledge);

    // Add custom statistics tracking
    $this->updateCustomMetrics($knowledge);
  }

  /**
   * Update custom metrics.
   */
  protected function updateCustomMetrics(KnowledgeInterface $knowledge) {
    // Track custom metrics
    // e.g., response time, quality score, etc.
    $metrics = $this->calculateMetrics($knowledge);

    // Store in custom table
    $this->database->merge('mymodule_knowledge_metrics')
      ->key(['kid' => $knowledge->id()])
      ->fields($metrics)
      ->execute();
  }

}

Creating an Event Subscriber

namespace Drupal\mymodule\EventSubscriber;

use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\knowledge\Event\KnowledgeEvents;
use Drupal\knowledge\Event\KnowledgeEvent;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;

/**
 * Knowledge event subscriber.
 */
class KnowledgeEventSubscriber implements EventSubscriberInterface {

  /**
   * The entity type manager.
   *
   * @var \Drupal\Core\Entity\EntityTypeManagerInterface
   */
  protected $entityTypeManager;

  /**
   * Constructs a new KnowledgeEventSubscriber.
   */
  public function __construct(EntityTypeManagerInterface $entity_type_manager) {
    $this->entityTypeManager = $entity_type_manager;
  }

  /**
   * {@inheritdoc}
   */
  public static function getSubscribedEvents() {
    $events[KnowledgeEvents::KNOWLEDGE_INSERT][] = ['onKnowledgeInsert'];
    $events[KnowledgeEvents::KNOWLEDGE_UPDATE][] = ['onKnowledgeUpdate'];
    return $events;
  }

  /**
   * Responds to knowledge insert event.
   */
  public function onKnowledgeInsert(KnowledgeEvent $event) {
    $knowledge = $event->getKnowledge();

    // Perform custom action
    \Drupal::logger('mymodule')->notice('New knowledge created: @id', [
      '@id' => $knowledge->id(),
    ]);

    // Trigger custom workflow
    $this->notifyStakeholders($knowledge);
  }

  /**
   * Responds to knowledge update event.
   */
  public function onKnowledgeUpdate(KnowledgeEvent $event) {
    $knowledge = $event->getKnowledge();

    // Check for significant changes
    if ($knowledge->hasField('field_important') && 
        $knowledge->get('field_important')->value) {
      $this->escalate($knowledge);
    }
  }

}

Creating a REST Resource

namespace Drupal\mymodule\Plugin\rest\resource;

use Drupal\knowledge\Entity\Knowledge;
use Drupal\rest\Plugin\ResourceBase;
use Drupal\rest\ResourceResponse;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;

/**
 * Provides a Knowledge REST Resource.
 *
 * @RestResource(
 *   id = "knowledge_resource",
 *   label = @Translation("Knowledge Resource"),
 *   uri_paths = {
 *     "canonical" = "/api/knowledge/{kid}",
 *     "create" = "/api/knowledge"
 *   }
 * )
 */
class KnowledgeResource extends ResourceBase {

  /**
   * Responds to GET requests.
   */
  public function get($kid) {
    $knowledge = Knowledge::load($kid);

    if (!$knowledge) {
      throw new NotFoundHttpException();
    }

    $response = [
      'id' => $knowledge->id(),
      'type' => $knowledge->bundle(),
      'incident_id' => $knowledge->getIncidentEntityId(),
      'entity_id' => $knowledge->getKnowledgeedEntityId(),
      'author' => $knowledge->getAuthorName(),
      'created' => $knowledge->getCreatedTime(),
    ];

    return new ResourceResponse($response);
  }

  /**
   * Responds to POST requests.
   */
  public function post(array $data) {
    // Validate and create knowledge entity
    $knowledge = Knowledge::create($data);
    $knowledge->save();

    return new ResourceResponse(['id' => $knowledge->id()], 201);
  }

}

Additional Resources

Code References

  • Entity definitions: src/Entity/
  • Services: src/Service/
  • Forms: src/Form/
  • Plugins: src/Plugin/
  • Tests: tests/src/

Further Reading

Contributing

To contribute to the Knowledge module:

  1. Review the issue queue: https://www.drupal.org/project/issues/knowledge
  2. Follow Drupal coding standards
  3. Include tests with patches
  4. Update documentation as needed

For questions or support, create an issue in the project's issue queue.