Created
June 3, 2022 09:14
-
-
Save vishalbandre/4849398da237c8fd386e668879016c3f to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
use Drupal\Core\Entity\EntityInterface; | |
use Drupal\field\Entity\FieldConfig; | |
use Drupal\field\Entity\FieldStorageConfig; | |
use Drupal\Core\Form\FormStateInterface; | |
use Drupal\Core\Entity\ContentEntityType; | |
use Drupal\Core\Routing\RouteMatchInterface; | |
/** | |
* Implements hook_help(). | |
*/ | |
function hashtags_help($route_name, RouteMatchInterface $route_match) { | |
switch ($route_name) { | |
case 'help.page.hashtags': | |
$output = ''; | |
$output .= '<h3>' . t('Hashtags') . '</h3>'; | |
$path = drupal_get_path('module', 'hashtags'); | |
$output .= '<p>' . t('The Hashtags module allows to create hashtags taxonomy terms | |
for the content entities. Go to <a href=":config">Hashtags | |
configuration page</a> and click on <b>Activate Hashtags</b> | |
button for the corresponding content type. This will create | |
<em>Hashtags taxonomy term</em> field and hashtags will be | |
activated for the <em>Body</em> field of the content type. | |
Also you can activate hashtags for other Text fields. To do | |
this go to the <b>Manage fields</b> of the content type, | |
click on <b>edit</b> link of the Text field and check the | |
<em>Hashtags Activate</em> box. <p>Check the images below to | |
see the tips how to configure the module.</p><div> | |
<div><img style="width:100%;" src=":hashtags1" /></div> | |
<div><img style="width:100%;" src=":hashtags2" /></div> | |
<div><img style="width:100%;" src=":hashtags3" /></div> | |
<div><img style="width:100%;" src=":hashtags4" /></div> | |
<div><img style="width:100%;" src=":hashtags5" /></div> | |
</div>', array(':config' => \Drupal::url('hashtags.manager_form'), | |
':hashtags1' => '/'.$path.'/images/hashtags1.png', | |
':hashtags2' => '/'.$path.'/images/hashtags2.png', | |
':hashtags3' => '/'.$path.'/images/hashtags3.png', | |
':hashtags4' => '/'.$path.'/images/hashtags4.png', | |
':hashtags5' => '/'.$path.'/images/hashtags5.png')) . '</p>'; | |
return $output; | |
} | |
} | |
/** | |
* Implements hook_form_alter(). | |
*/ | |
function hashtags_form_alter(&$form, FormStateInterface $form_state, $form_id) { | |
if ($form_state->getFormObject() instanceof \Drupal\Core\Entity\EntityFormInterface) { | |
$entity = $form_state->getFormObject()->getEntity(); | |
$entity_type = $entity->getEntityTypeId(); | |
$bundle = $entity->bundle(); | |
$config = \Drupal::config('hashtags.settings'); | |
$hashtags_field_name = $config->get('hashtags_taxonomy_terms_field_name'); | |
if (!_hashtags_is_field_exists($entity_type, $bundle, $hashtags_field_name)) { | |
return; | |
} | |
$hide_field_hashtags = $config->get('hide_field_hashtags'); | |
if (isset($form[$hashtags_field_name])) { | |
$form[$hashtags_field_name]['#access'] = !$hide_field_hashtags; | |
} | |
} | |
} | |
/** | |
* Implements hook_form_field_config_edit_form_alter(). | |
*/ | |
function hashtags_form_field_config_edit_form_alter(&$form, FormStateInterface $form_state) { | |
if (!\Drupal::currentUser()->hasPermission('administer hashtags')) { | |
return; | |
} | |
$field = $form_state->getFormObject()->getEntity(); | |
$entity_type = $field->getTargetEntityTypeId(); | |
$bundle = $field->getTargetBundle(); | |
$field_type = $field->getType(); | |
$config = \Drupal::config('hashtags.settings'); | |
$hashtags_field_name = $config->get('hashtags_taxonomy_terms_field_name'); | |
if (in_array($field_type, _hashtags_get_field_text_types()) && | |
_hashtags_is_field_exists($entity_type, $bundle, $hashtags_field_name)) { | |
$form['field']['hashtags'] = [ | |
'#type' => 'fieldset', | |
'#title' => t('Hashtags'), | |
'#collapsible' => TRUE, | |
'#collapsed' => FALSE, | |
]; | |
$form['field']['hashtags']['hashtags_activate'] = [ | |
'#type' => 'checkbox', | |
'#title' => t('Activate'), | |
'#description' => t('This allows to use hashtags for this field.'), | |
'#default_value' => $field->getThirdPartySetting('hashtags', 'hashtags_activate', FALSE), | |
]; | |
$form['actions']['submit']['#submit'][] = 'hashtags_form_field_config_edit_form_submit'; | |
} | |
} | |
/** | |
* Form submission handler for hashtags_form_field_config_edit_form_alter. | |
* | |
* @param array $form | |
* The form array. | |
* @param FormStateInterface $form_state | |
* The form state. | |
*/ | |
function hashtags_form_field_config_edit_form_submit(array $form, FormStateInterface $form_state) { | |
$field = $form_state->getFormObject()->getEntity(); | |
$form_fields = &$form_state->getValues(); | |
// If the private option is checked, update settings. | |
if ($form_fields['hashtags_activate']) { | |
$field->setThirdPartySetting('hashtags', 'hashtags_activate', TRUE); | |
$field->save(); | |
} | |
else { | |
$field->unsetThirdPartySetting('hashtags', 'hashtags_activate'); | |
$field->save(); | |
} | |
} | |
/** | |
* Implements hook_entity_presave(). | |
*/ | |
function hashtags_entity_presave(EntityInterface $entity) { | |
$config = \Drupal::config('hashtags.settings'); | |
$hashtags_field_name = $config->get('hashtags_taxonomy_terms_field_name'); | |
$hashtags_vid = $config->get('hashtags_vid'); | |
$entity_type = $entity->getEntityTypeId(); | |
$bundle = $entity->bundle(); | |
if (!_hashtags_is_field_exists($entity_type, $bundle, $hashtags_field_name)) { | |
return; | |
} | |
$vid = $config->get('hashtags_vid'); | |
$text = ''; | |
$activated_text_fields = _hashtags_get_activated_text_fields($entity_type, $bundle); | |
foreach ($activated_text_fields as $field_name) { | |
foreach ($entity->{$field_name} as $item) { | |
$text .= ' '. $item->value; | |
} | |
} | |
/*** | |
* Proposed solution. | |
* Reset hashtags field. | |
*/ | |
$entity->set($hashtags_field_name, NULL); | |
/** | |
* TLDR; | |
*/ | |
// get field | |
$field = $entity->get($hashtags_field_name); | |
// get logger | |
$logger = \Drupal::logger('hashtags'); | |
/** | |
* Algorithm: | |
* | |
* 1. Get hashtags from existing entity. | |
* 2. Remove all old hashtags from entity field. | |
* 2. Get all hashtags from the text (updated). | |
* 3. Add all the hashtags to hashtags field for entity. | |
*/ | |
/** | |
* Algorithm 1: Get everything about an entity. | |
* 1. Get current entity meta. | |
* 2. Get current entity fields. | |
*/ | |
// Get fields for current entity. | |
// works. | |
$entity_fields = $entity->getFields(); | |
$str = ''; | |
foreach($entity_fields as $ef) { | |
$str .= $ef->getName() . ' '; | |
} | |
//$logger->warning('<pre><code>Here: c '. $str .' /Here</code></pre>'); | |
// works end. | |
// Get specific field_hashtags | |
$field_hashtags = $entity->get($hashtags_field_name); | |
// get field name | |
$tmp = ''; | |
$field_name = $field_hashtags->getName(); | |
$values = $field_hashtags->getValue(); | |
foreach($values as $val) { | |
// $tmp .= print_r($val, TRUE) . ' '; | |
foreach($val as $v) { | |
$tmp .= print_r($v, TRUE) . ' '; | |
} | |
} | |
$logger->warning('<pre><code>Here (New): '. $tmp .' /Here</code></pre>'); | |
// Get all the fields associated with current entity | |
/* | |
$field_map = \Drupal::entityManager()->getFieldMap(); | |
$node_field_map = $field_map['node']; | |
$node_fields = array_keys($node_field_map['node']); | |
*/ | |
// 1. Get hashtags from existing entity. | |
/* | |
$hashtags = []; | |
$hashtags_string = ''; | |
$hashtags_field = $entity->{$hashtags_field_name}; | |
foreach ($hashtags_field as $item) { | |
$hashtags[] = $item->name; | |
$hashtags_string .= ' new ' . $item->name; | |
} | |
*/ | |
// 2. Remove all old hashtags from entity field. | |
//$hashtags = $entity->{$hashtags_field_name} = []; | |
// get current entity id | |
$entity_id = $entity->id(); | |
// Get all hashtag terms related to this $entity_id | |
//$terms = \Drupal::entityTypeManager()->getStorage('taxonomy_term')->loadByProperties(['entity_id' => $entity_id]); | |
/** | |
* TLDR CLOSE; | |
*/ | |
$tags = _hashtags_parse_tags($text, FALSE); | |
$tag_ids = []; | |
if (!$tags) { | |
return; | |
} | |
/* | |
* TLDR; | |
* Get all existing tags. | |
* | |
* Remove traces to old one. | |
* Add new ones. | |
*/ | |
// Get all existing hashtag terms associated with this $entity | |
/* | |
$type = gettype($tags); | |
$tgs = ''; | |
foreach($tags as $tag) { | |
$tgs .= $tag.', '; | |
} | |
*/ | |
$terms_backup = ''; | |
/** | |
* TLDR CLOSE; | |
*/ | |
foreach ($tags as $tag_name) { | |
$terms = \Drupal::entityTypeManager() | |
->getStorage('taxonomy_term') | |
->loadByProperties(['name' => $tag_name]); | |
$terms_backup = $terms; | |
foreach($terms as $term) { | |
$tid = $term->id(); | |
_hashtags_field_remove_term($field, $tid); | |
} | |
$logger->warning('<pre><code>Last tid: '. print_r($tid, TRUE) .' /Here</code></pre>'); | |
$term = reset($terms); | |
if (empty($term)) { | |
$term = \Drupal\taxonomy\Entity\Term::create([ | |
'name' => $tag_name, | |
'vid' => $vid, | |
]); | |
$term->save(); | |
} | |
$tag_ids[] = $term->id(); | |
} | |
//$logger->warning('<pre><code>Here (Attach): '. print_r($terms_backup, TRUE) .' /Here</code></pre>'); | |
_hashtags_field_attach_terms($entity->{$hashtags_field_name}, $tag_ids, $hashtags_vid); | |
} | |
/** | |
* Get taxonomy term ids by text that contains hashtags | |
* @param $text | |
* @return array | |
*/ | |
function _hashtags_get_tids_by_text($text) { | |
$tags = _hashtags_parse_tags($text, FALSE); | |
$tag_ids = []; | |
if (!$tags) { | |
return $tag_ids; | |
} | |
foreach ($tags as $tag_name) { | |
$terms = \Drupal::entityTypeManager() | |
->getStorage('taxonomy_term') | |
->loadByProperties(['name' => $tag_name]); | |
$term = reset($terms); | |
if (!empty($term)) { | |
$tag_ids[strtolower($tag_name)] = $term->id(); | |
} | |
} | |
return $tag_ids; | |
} | |
/** | |
* Get field Text types that are avaiable for hashtags activation | |
* @return array | |
* | |
*/ | |
function _hashtags_get_field_text_types() { | |
return array( | |
'text', | |
'text_long', | |
'text_with_summary', | |
'string', | |
'string_long' | |
); | |
} | |
/** | |
* Check weither a hashtags feature is activated for passed field (text) | |
* @param $entity_type | |
* @param $bundle | |
* @param $field_name | |
* @return boolean | |
*/ | |
function _hashtags_is_field_activated($entity_type, $bundle, $field_name) { | |
$field = \Drupal::entityTypeManager()->getStorage('field_config')->load("{$entity_type}.{$bundle}.{$field_name}"); | |
return $field->getThirdPartySetting('hashtags', 'hashtags_activate', FALSE); | |
} | |
/** | |
* Check if field storage / field exist | |
* @param $entity_type | |
* @param $bundle | |
* @param $field_name | |
* @return bool|static | |
*/ | |
function _hashtags_is_field_exists($entity_type, $bundle, $field_name) { | |
$field_storage = FieldStorageConfig::loadByName($entity_type, $field_name); | |
if (empty($field_storage)) { | |
return FALSE; | |
} | |
$field = FieldConfig::loadByName($entity_type, $bundle, $field_name); | |
if (empty($field)) { | |
return FALSE; | |
} | |
return $field; | |
} | |
/** | |
* Helper function that attach a term to the taxonomy terms hashtags field | |
* @param $field | |
* @param $tid | |
* @param string $vid | |
*/ | |
function _hashtags_field_attach_term($field, $tid, $vid = 'hashtags') { | |
// create term and attach to the field | |
$hashtags = $field->getValue(); | |
$hashtags[] = array('target_id' => $tid); | |
$field->setValue($hashtags); | |
} | |
/** | |
* Helper function that attach a number of terms to the taxonomy terms hashtags field | |
* @param $field | |
* @param $tids | |
* @param string $vid | |
*/ | |
function _hashtags_field_attach_terms($field, $tids, $vid = 'hashtags') { | |
// create term and attach to the field | |
$hashtags = array(); | |
foreach ($tids as $tid) { | |
$hashtags[] = array('target_id' => $tid); | |
} | |
$field->setValue($hashtags); | |
} | |
/** | |
* Helper function that remove a term from the taxonomy terms hashtags field | |
* @param $field | |
* @param $tid | |
* @param string $vid | |
*/ | |
function _hashtags_field_remove_term($field, $tid) { | |
$hashtags = $field->getValue(); | |
$key = _hashtags_get_tt_key($hashtags, $tid); | |
unset($hashtags[$key]); | |
$field->setValue($hashtags); | |
} | |
/** | |
* Get taxonomy term key from the array of term values. | |
* | |
* @param $tags term values that are returned with .getValue() | |
* Format: | |
* [ 0 => [ target_id: tid1 ], 1 => [ target_id: tid2 ] ] | |
* @param $property_value - term id that should be found | |
* @param $property_name - 'target_id' by default | |
* @return - the key of the term id | |
*/ | |
function _hashtags_get_tt_key($tags, $property_value, $property_name = 'target_id') { | |
return array_search( | |
$property_value, | |
array_filter( | |
array_combine( | |
array_keys($tags), | |
array_column( | |
$tags, $property_name | |
) | |
) | |
) | |
); | |
} | |
/** | |
* Parse a string and return an array or comma-separated | |
* string of tags depending on the mode (second parameter) | |
* @param $text | |
* @param bool $is_string_return | |
* @param bool $capture_position | |
* @return array|string | |
*/ | |
function _hashtags_parse_tags($text, $is_string_return = TRUE, $capture_position = FALSE) { | |
// capture_position == PREG_OFFSET_CAPTURE; | |
// save position to avoid replacing hashtags | |
// inside links (<a href="#ball">) | |
$flag = $capture_position ? PREG_OFFSET_CAPTURE : PREG_PATTERN_ORDER; | |
$tags_list = array(); | |
// 1) 2+ character after # | |
// 2) Don't start with or use only numbers (0-9) (#123abc, #123 etc) | |
// 3) Letters - digits work correct (#abc123, #conference2013) | |
// 4) No Special Characters “!, $, %, ^, &, *, +, .” | |
// 5) No Spaces | |
// 6) May use an underscore. Hyphens and dashes will not work. | |
// 7) <p>#hashtag</p> - is valid | |
// 8) <a href="#hashtag">Link</p> - is not valid | |
$pattern = "/[\s>]+?#([[:alpha:]][[:alnum:]_]*[^<\s[:punct:]])/iu"; | |
// add <htest> to process first #hastag - string beginning | |
preg_match_all($pattern, '<htest>'.$text.'<htest>', $tags_list, $flag); | |
// no hashtags has been found | |
if (isset($tags_list[0]) && !sizeof($tags_list[0])) { | |
if ($is_string_return) { | |
return ''; | |
} | |
return array(); | |
} | |
// save position | |
if ($capture_position) { | |
foreach ($tags_list[1] as $key => $data) { | |
$result[$data[1]] = strtolower($data[0]); | |
} | |
} else { | |
// turn tags into lowercase | |
foreach ($tags_list[1] as $key => $tag) { | |
$tags_list[1][$key] = strtolower($tag); | |
} | |
if ($is_string_return) { | |
$result = implode(',', $tags_list[1]); | |
} else { | |
$result = $tags_list[1]; | |
} | |
} | |
return array_unique($result); | |
} | |
/** | |
* Get entity type label by entity type id. | |
* @param $entity_type | |
*/ | |
function _hashtags_get_entity_type_label($entity_type) { | |
return \Drupal::entityTypeManager() | |
->getStorage($entity_type) | |
->getEntityType() | |
->getLabel(); | |
} | |
/** | |
* Get bundle label by entity type id and bundle id. | |
* @param $entity_type | |
* @param $bundle | |
*/ | |
function _hashtags_get_bundle_label($entity_type, $bundle) { | |
return \Drupal::service("entity_type.bundle.info") | |
->getAllBundleInfo()[$entity_type][$bundle]['label']; | |
} | |
/** | |
* Get Content Entity Types | |
* @param array $excluded_types | |
* @return array | |
*/ | |
function _hashtags_get_content_entity_types($excluded_types = [ | |
'block_content', | |
'contact_message', | |
'file', | |
'shortcut', | |
'menu_link_content' | |
]) { | |
$definitions = \Drupal::entityTypeManager()->getDefinitions(); | |
$types = []; | |
foreach ($definitions as $id => $definition) { | |
if ($definition instanceof ContentEntityType && !in_array($id, $excluded_types)) { | |
$types[$id] = $id; | |
} | |
} | |
return $types; | |
} | |
/** | |
* Get the field names of the Text type that have Hashtags flag activated | |
* @param $entity_type | |
* @param $bundle | |
* @return array | |
*/ | |
function _hashtags_get_activated_text_fields($entity_type, $bundle) { | |
$fields =\Drupal::entityManager()->getFieldDefinitions($entity_type, $bundle); | |
$activated_text_fields = []; | |
foreach ($fields as $field) { | |
// check if a field is added through Manage Fields (FieldConfig class) | |
// and it has one of the Text types | |
$field_name = $field->getName(); | |
if ($field instanceof FieldConfig && | |
in_array($field->getType(), _hashtags_get_field_text_types()) && | |
_hashtags_is_field_activated($entity_type, $bundle, $field_name)) { | |
$activated_text_fields[] = $field_name; | |
} | |
} | |
return $activated_text_fields; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment