This commit is contained in:
calcu1on 2025-03-15 17:25:17 -04:00
parent 9dbfbeecef
commit d38d4aabc1
105 changed files with 2469 additions and 1484 deletions

View File

@ -19,11 +19,14 @@
"cweagans/composer-patches": "^1.7",
"drupal/admin_toolbar": "^3.4",
"drupal/better_exposed_filters": "^7.0",
"drupal/ckeditor5_plugin_pack": "^1.2",
"drupal/color_field": "^3.0",
"drupal/config_split": "^2.0",
"drupal/core-composer-scaffold": "^11",
"drupal/core-project-message": "^11",
"drupal/core-recommended": "^11",
"drupal/devel": "^5.3",
"drupal/easy_breadcrumb": "^2.0",
"drupal/entity_clone": "^2.1@beta",
"drupal/entity_hierarchy": "^3.3",
"drupal/field_group": "^3.4",
@ -50,6 +53,7 @@
"drupal/workflow": "^1.8",
"drush/drush": "^13",
"mglaman/composer-drupal-lenient": "^1.0",
"symfony/http-client": "^6.4",
"symfony/process": "^7.1",
"weitzman/drupal-test-traits": "^2.5"
},

1517
composer.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="#FFFFFF"><path d="M200-120q-33 0-56.5-23.5T120-200v-560q0-33 23.5-56.5T200-840h560q33 0 56.5 23.5T840-760v560q0 33-23.5 56.5T760-120H200Zm0-80h560v-480H200v480Zm280-80q-82 0-146.5-44.5T240-440q29-71 93.5-115.5T480-600q82 0 146.5 44.5T720-440q-29 71-93.5 115.5T480-280Zm0-60q56 0 102-26.5t72-73.5q-26-47-72-73.5T480-540q-56 0-102 26.5T306-440q26 47 72 73.5T480-340Zm0-100Zm0 60q25 0 42.5-17.5T540-440q0-25-17.5-42.5T480-500q-25 0-42.5 17.5T420-440q0 25 17.5 42.5T480-380Z"/></svg>

After

Width:  |  Height:  |  Size: 577 B

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="#000000"><path d="M200-120q-33 0-56.5-23.5T120-200v-560q0-33 23.5-56.5T200-840h560q33 0 56.5 23.5T840-760v560q0 33-23.5 56.5T760-120H200Zm0-80h560v-480H200v480Zm280-80q-82 0-146.5-44.5T240-440q29-71 93.5-115.5T480-600q82 0 146.5 44.5T720-440q-29 71-93.5 115.5T480-280Zm0-60q56 0 102-26.5t72-73.5q-26-47-72-73.5T480-540q-56 0-102 26.5T306-440q26 47 72 73.5T480-340Zm0-100Zm0 60q25 0 42.5-17.5T540-440q0-25-17.5-42.5T480-500q-25 0-42.5 17.5T420-440q0 25 17.5 42.5T480-380Z"/></svg>

After

Width:  |  Height:  |  Size: 577 B

View File

@ -0,0 +1,5 @@
name: Block Content Preview
description: 'Allows loading of preview images for inline blocks.'
core_version_requirement: ^10 || ^11
type: module
package: Layout Builder

View File

@ -0,0 +1,11 @@
assets:
css:
theme:
css/block-content-preview.css: {}
js:
js/contentBlockPreview.js: { defer: true }
dependencies:
- core/jquery
- core/once
- core/drupal

View File

@ -0,0 +1,11 @@
<?php
/**
* Implements hook form alter.
*/
function content_block_preview_element_info_alter(array &$types) {
if (isset($types['layout_builder'])) {
$types['layout_builder']['#attached']['library'][] = 'content_block_preview/assets';
}
}

View File

@ -0,0 +1,18 @@
#drupal-off-canvas .inline-block-list li a:hover:after {
background-image: url('/modules/custom/content_block_preview/assets/preview-white.svg');
background-size: cover;
background-position: center;
background-repeat: no-repeat;
content: '';
display: block;
max-width: 25px;
width: 25px;
height: 25px;
position: absolute;
top: 50%;
right: 10px;
transform: translateY(-50%);
z-index: 99999999;
pointer-events: all;
}

View File

@ -0,0 +1,11 @@
(function (Drupal, once) {
Drupal.behaviors.dialog = {
attach: function (context, settings) {
let settingsTray = once('contentBlockPreview', '#drupal-off-canvas', context);
console.log(settingsTray);
settingsTray.forEach((tray) => {
console.log("hello");
});
}
};
})(Drupal, once);

View File

@ -1,5 +1,7 @@
<?php
use Drupal\views\ViewExecutable;
function dc_core_page_attachments(array &$attachments) {
if (\Drupal::service('router.admin_context')->isAdminRoute()) {
$attachments['#attached']['library'][] = 'dc_core/admin_overrides';
@ -8,3 +10,30 @@ function dc_core_page_attachments(array &$attachments) {
$attachments['#attached']['library'][] = 'dc_core/admin_overrides';
}
}
function dc_core_views_pre_view(ViewExecutable $view) {
if ($view->id() !== 'floorplans_by_property') {
return;
}
$cur_node = \Drupal::routeMatch()->getParameter('node');
if (!$cur_node instanceof \Drupal\node\NodeInterface) {
return;
}
if (!$cur_node->hasField('field_property')) {
return;
}
// current property.
$property = $cur_node->get('field_property')->first()->getValue()['target_id'] ?? FALSE;
assert(!is_null($property));
$increased_price_data = [
];
$exposed_input = $view->getExposedInput();
if (isset($exposed_input['field_price_value'])) {
$filters = $view->display_handler->getOption('filters');
$filters['field_price_value']['group_info']['group_items'][3]['title'] = "339+";
$filters['field_price_value']['group_info']['group_items'][3]['value']['value'] = 339;
$view->display_handler->overrideOption('filters', $filters);
}
}

View File

@ -0,0 +1,7 @@
dc_core.lotr_characters:
path: '/api/character-list'
defaults:
_controller: '\Drupal\dc_core\Controller\LotrCharacters::characterJson'
_title: 'LOTR | Characters'
requirements:
_permission: 'access content'

View File

@ -0,0 +1,5 @@
services:
dc_core.commands:
class: \Drupal\dc_core\Drush\Commands\CharacterImport
tags:
- { name: drush.command }

View File

@ -0,0 +1,420 @@
<?php
namespace Drupal\dc_core\Attributes;
trait LotrCharacterList {
public $characterList;
public function __construct() {
$characters = $this->getCharacterJson();
foreach ($characters as $index => $character) {
$rand = rand(0,2);
if ($rand == 1) {
$characters[$index]['last_modified'] = time();
}
else {
$characters[$index]['last_modified'] = 0;
}
}
$this->characterList = $characters;
}
protected function getCharacterJson(): array {
$characters = [
[
'name' => 'Frodo Baggins',
'species' => 'Hobbit',
'height' => '3\'6" (1.07m)',
'hair' => 'Brown',
'eyes' => 'Blue',
'birth' => '2968 of the Third Age',
'death' => 'Unknown, last seen leaving Middle-earth',
'title' => 'Ring-bearer',
'occupation' => 'Adventurer',
'affiliation' => 'The Fellowship of the Ring',
'bio' => 'Frodo Baggins was a Hobbit of the Shire who was entrusted with the One Ring by his uncle, Bilbo. A reluctant hero, he embarked on a perilous journey to destroy the Ring in the fires of Mount Doom. His quest was fraught with challenges, from the deceptive Gollum to the looming threat of Saurons forces. Despite his bravery, the burden of the Ring ultimately took its toll on him, leading to his eventual departure from Middle-earth.',
'image_url' => 'https://platform.polygon.com/wp-content/uploads/sites/2/chorus/uploads/chorus_asset/file/22263166/lotr3_movie_screencaps.com_10384.jpg',
'youtube_url' => 'https://www.youtube.com/embed/1Hd-ULcdNN0'
],
[
'name' => 'Aragorn',
'species' => 'Human',
'height' => '6\'6" (1.98m)',
'hair' => 'Dark brown',
'eyes' => 'Grey',
'birth' => '2931 of the Third Age',
'death' => '120 of the Fourth Age',
'title' => 'King Elessar',
'occupation' => 'Ranger, King',
'affiliation' => 'The Fellowship of the Ring, Kingdom of Gondor',
'bio' => 'Aragorn, son of Arathorn, was the heir to the throne of Gondor. He lived much of his life as a ranger, known as Strider, before stepping into his destiny as the leader of the forces against Sauron. A skilled warrior and tracker, he was instrumental in the success of the Fellowship and played a key role in uniting the Free Peoples of Middle-earth against the Dark Lord. After the defeat of Sauron, Aragorn ascended to the throne of Gondor and ruled with wisdom and strength.',
'image_url' => 'https://vignette.wikia.nocookie.net/lotr/images/5/53/Aragorn_1.png/revision/latest/scale-to-width-down/350?cb=20190520050210',
'youtube_url' => 'https://www.youtube.com/watch?v=Qx62l9Pa2uI'
],
[
'name' => 'Gandalf',
'species' => 'Maia (Spirit)',
'height' => '5\'6" (1.68m)',
'hair' => 'Grey, White later',
'eyes' => 'Grey',
'birth' => 'Uncertain, an ancient Maia spirit',
'death' => 'Deceased, but returned as Gandalf the White',
'title' => 'Gandalf the Grey',
'occupation' => 'Wizard',
'affiliation' => 'The Fellowship of the Ring',
'bio' => 'Gandalf is one of the five Istari sent by the Valar to aid the Free Peoples of Middle-earth. He is a wise and powerful wizard, often serving as a counselor and guiding force in key moments of the War of the Ring. Gandalf helped organize the Fellowship and played a central role in defeating Saurons forces. After falling in battle with the Balrog, Gandalf was resurrected as Gandalf the White, more powerful than before. His wisdom, courage, and leadership were vital in the defeat of Sauron.',
'image_url' => 'https://vignette.wikia.nocookie.net/lotr/images/a/a6/Gandalf_the_Grey.png/revision/latest/scale-to-width-down/350?cb=20200814044030',
'youtube_url' => 'https://www.youtube.com/watch?v=eYhwdf41gMI'
],
[
'name' => 'Legolas',
'species' => 'Elf',
'height' => '6\'1" (1.85m)',
'hair' => 'Blonde',
'eyes' => 'Blue',
'birth' => 'Unknown, during the First Age',
'death' => 'Unknown, likely still alive in the Fourth Age',
'title' => 'Prince of Mirkwood',
'occupation' => 'Archer, Prince',
'affiliation' => 'The Fellowship of the Ring, Mirkwood Elves',
'bio' => 'Legolas is an Elven prince from Mirkwood and one of the members of the Fellowship of the Ring. His remarkable skills with a bow and arrow were invaluable in battle, and his keen senses allowed him to spot danger before it struck. Along with Gimli, Legolas formed a deep friendship despite the ancient animosity between Elves and Dwarves. He was also instrumental in the battle against Saurons forces, and after the War of the Ring, he sailed west to the Undying Lands.',
'image_url' => 'https://vignette.wikia.nocookie.net/lotr/images/4/4a/Legolas_The_Lord_of_the_Rings_Animated.png/revision/latest/scale-to-width-down/350?cb=20190917132524',
'youtube_url' => 'https://www.youtube.com/watch?v=xwFZ0osEjfY'
],
[
'name' => 'Gimli',
'species' => 'Dwarf',
'height' => '4\'4" (1.32m)',
'hair' => 'Red',
'eyes' => 'Brown',
'birth' => '2879 of the Third Age',
'death' => 'Unknown, possibly still alive in the Fourth Age',
'title' => 'Son of Glóin',
'occupation' => 'Warrior',
'affiliation' => 'The Fellowship of the Ring',
'bio' => 'Gimli, son of Glóin, was a Dwarf warrior from Erebor who joined the Fellowship to aid in the destruction of the One Ring. Known for his strength and bravery, Gimlis friendship with Legolas grew throughout their journey, symbolizing the union between Elves and Dwarves. He played a key role in several battles, including the Battle of Helms Deep and the Battle of the Pelennor Fields. After the War of the Ring, Gimli became a leader of Dwarves and visited the Glittering Caves of Helms Deep.',
'image_url' => 'https://vignette.wikia.nocookie.net/lotr/images/a/a2/Gimli.png/revision/latest/scale-to-width-down/350?cb=20190617045757',
'youtube_url' => 'https://www.youtube.com/watch?v=H7ti80IzTME'
],
[
'name' => 'Samwise Gamgee',
'species' => 'Hobbit',
'height' => '3\'6" (1.07m)',
'hair' => 'Brown',
'eyes' => 'Brown',
'birth' => '2980 of the Third Age',
'death' => 'Unknown, last seen leaving Middle-earth',
'title' => 'Gardener, Ring-bearer',
'occupation' => 'Gardener, Adventurer',
'affiliation' => 'The Fellowship of the Ring',
'bio' => 'Samwise Gamgee was Frodo Baggins loyal gardener and friend. Though initially seen as a simple Hobbit, Sam proved to be one of the most steadfast and courageous members of the Fellowship. He played a crucial role in helping Frodo destroy the One Ring, even carrying him at times when Frodo could go no further. Sams loyalty and friendship were essential in the success of the quest, and he eventually returned to the Shire to live a full life before sailing to the Undying Lands.',
'image_url' => 'https://vignette.wikia.nocookie.net/lotr/images/d/d6/Samwise_Gamgee_animated.png/revision/latest/scale-to-width-down/350?cb=20181217044906',
'youtube_url' => 'https://www.youtube.com/watch?v=1Nx3zRx7pHk'
],
[
'name' => 'Boromir',
'species' => 'Human',
'height' => '6\'1" (1.85m)',
'hair' => 'Brown',
'eyes' => 'Grey',
'birth' => '2978 of the Third Age',
'death' => '3019 of the Third Age (Killed by Orcs)',
'title' => 'Captain of Gondor',
'occupation' => 'Soldier',
'affiliation' => 'The Fellowship of the Ring',
'bio' => 'Boromir was the eldest son of Denethor, the Steward of Gondor. A brave and noble warrior, Boromir was chosen to be part of the Fellowship of the Ring. However, his desire to use the Ring to save Gondor led to his tragic fall. In the end, he redeemed himself by defending Merry and Pippin from the attacking Uruk-hai, dying heroically. His death marked one of the most poignant moments of the War of the Ring.',
'image_url' => 'https://vignette.wikia.nocookie.net/lotr/images/6/69/Boromir.png/revision/latest/scale-to-width-down/350?cb=20190602141523',
'youtube_url' => 'https://www.youtube.com/watch?v=0fvUzz56N0E'
],
[
'name' => 'Galadriel',
'species' => 'Elf',
'height' => '5\'11" (1.80m)',
'hair' => 'Blonde',
'eyes' => 'Grey',
'birth' => 'Uncertain, during the Years of the Trees',
'death' => 'Unknown, likely still alive in the Fourth Age',
'title' => 'Lady of Lothlórien',
'occupation' => 'Queen, Ruler of Lothlórien',
'affiliation' => 'The Free Peoples of Middle-earth',
'bio' => 'Galadriel is one of the oldest and most powerful Elves in Middle-earth. A member of the royal house of the Noldor, she ruled over the realm of Lothlórien with her husband Celeborn. Galadriels wisdom, beauty, and grace were unmatched, and she played a vital role in aiding the Fellowship, providing them with gifts and counsel. Her Elven ring, Nenya, helped preserve the beauty of Lothlórien. After the defeat of Sauron, Galadriel sailed to the Undying Lands.',
'image_url' => 'https://vignette.wikia.nocookie.net/lotr/images/d/d1/Galadriel.png/revision/latest/scale-to-width-down/350?cb=20200118073639',
'youtube_url' => 'https://www.youtube.com/watch?v=nHzEFdqT27Q'
],
[
'name' => 'Saruman',
'species' => 'Maia (Spirit)',
'height' => '5\'8" (1.73m)',
'hair' => 'White, later Grey',
'eyes' => 'Grey',
'birth' => 'Uncertain, ancient Maia spirit',
'death' => 'Fell in 3019 of the Third Age',
'title' => 'Saruman the White',
'occupation' => 'Wizard, Leader of Isengard',
'affiliation' => 'Previously the White Council, later Sauron',
'bio' => 'Saruman was one of the five Istari sent to Middle-earth to help oppose Sauron. Initially the head of the White Council and the most powerful of the wizards, he became corrupted by his desire for power. Saruman sought to gain control over the One Ring and betrayed the Free Peoples of Middle-earth, forging an alliance with Sauron. His quest for domination led to his downfall when his forces were defeated at Helms Deep and his fortress of Isengard was destroyed. Sarumans ambition ultimately led to his tragic end.',
'image_url' => 'https://vignette.wikia.nocookie.net/lotr/images/9/97/Saruman.png/revision/latest/scale-to-width-down/350?cb=20190707163339',
'youtube_url' => 'https://www.youtube.com/watch?v=5Hjq8azf0As'
],
[
'name' => 'Gollum',
'species' => 'Stoor Hobbit (Deformed by the Ring)',
'height' => '4\'0" (1.22m)',
'hair' => 'Brown',
'eyes' => 'Yellow',
'birth' => '2430 of the Third Age',
'death' => '3019 of the Third Age (fell into Mount Doom)',
'title' => 'Gollum (Sméagol)',
'occupation' => 'Former Hobbit, Ring-bearer (for a time)',
'affiliation' => 'None, though he briefly aided Frodo',
'bio' => 'Gollum, originally named Sméagol, was a Stoor Hobbit who found the One Ring and was consumed by it. The Ring corrupted him, turning him into the creature known as Gollum. His obsession with the Ring led to the murder of his friend Deagol, and he was forever marked by his betrayal. Over centuries, Gollum lived a tortured existence, seeking the Ring but also despising it. His split personality, Sméagol and Gollum, created a constant inner battle. Gollum played a pivotal role in the destruction of the Ring, though tragically, he took it back just before falling into the fires of Mount Doom.',
'image_url' => 'https://vignette.wikia.nocookie.net/lotr/images/7/77/Gollum.png/revision/latest/scale-to-width-down/350?cb=20190602141623',
'youtube_url' => 'https://www.youtube.com/watch?v=1O0Xbqp7cnE'
],
[
'name' => 'Elrond',
'species' => 'Half-Elf',
'height' => '6\'0" (1.83m)',
'hair' => 'Brown',
'eyes' => 'Grey',
'birth' => 'First Age',
'death' => 'Unknown, likely still alive in the Fourth Age',
'title' => 'Lord of Rivendell',
'occupation' => 'Ruler of Rivendell',
'affiliation' => 'The Free Peoples of Middle-earth',
'bio' => 'Elrond is a Half-Elf and the Lord of Rivendell. A key figure in the struggle against Sauron, he was known for his wisdom and leadership. Elrond played an essential role in both the formation of the Fellowship of the Ring and in the Battle of the Last Alliance. He also helped raise Aragorn, and his counsel was crucial to the success of the War of the Ring. Elronds heritage as both a descendant of Elves and Men made him uniquely equipped to guide the future of Middle-earth. After the Rings destruction, he sailed west to the Undying Lands.',
'image_url' => 'https://vignette.wikia.nocookie.net/lotr/images/a/a9/Elrond.png/revision/latest/scale-to-width-down/350?cb=20190507161536',
'youtube_url' => 'https://www.youtube.com/watch?v=kXAlrl0lOdw'
],
[
'name' => 'Bilbo Baggins',
'species' => 'Hobbit',
'height' => '3\'6" (1.07m)',
'hair' => 'Brown',
'eyes' => 'Blue',
'birth' => '2890 of the Third Age',
'death' => 'Unknown, last seen sailing to the Undying Lands',
'title' => 'The Mad Baggins, Ring-bearer',
'occupation' => 'Adventurer, Burglar',
'affiliation' => 'The Fellowship of the Ring, Thorin\'s Company',
'bio' => 'Bilbo Baggins was a Hobbit from the Shire who found the One Ring during an unexpected adventure with Thorin Oakenshield and his company of dwarves. This encounter, which began as a simple adventure, would change his life and the fate of Middle-earth. Bilbo kept the Ring for many years, unaware of its true power, but the discovery of the Ring set in motion the events of the War of the Ring. Bilbo later passed the Ring to his nephew, Frodo, and retired to Rivendell, where he lived out his remaining years before sailing west.',
'image_url' => 'https://vignette.wikia.nocookie.net/lotr/images/d/d2/Bilbo_Baggins.png/revision/latest/scale-to-width-down/350?cb=20190617101623',
'youtube_url' => 'https://www.youtube.com/watch?v=zG1PzRJLUZ4'
],
[
'name' => 'Arwen',
'species' => 'Elf',
'height' => '5\'6" (1.68m)',
'hair' => 'Brown',
'eyes' => 'Grey',
'birth' => '2941 of the Third Age',
'death' => 'Unknown, sails to the Undying Lands after Aragorns death',
'title' => 'Evenstar of Rivendell',
'occupation' => 'Princess of Rivendell',
'affiliation' => 'The Free Peoples of Middle-earth',
'bio' => 'Arwen Undómiel was an Elven princess and the daughter of Elrond. She was famed for her beauty and wisdom, but also for her deep love for Aragorn. Arwens choice to forsake her immortality and marry Aragorn was one of the most significant acts in the fight against Sauron. Her love for Aragorn played a pivotal role in inspiring him to take up his destiny as King of Gondor. After the Ring was destroyed, Arwen chose to live out her remaining years with Aragorn before eventually sailing to the Undying Lands after his death.',
'image_url' => 'https://vignette.wikia.nocookie.net/lotr/images/0/01/Arwen.png/revision/latest/scale-to-width-down/350?cb=20190619134045',
'youtube_url' => 'https://www.youtube.com/watch?v=PEt93XqcnWI'
],
[
'name' => 'Théoden',
'species' => 'Human',
'height' => '5\'11" (1.80m)',
'hair' => 'Blonde',
'eyes' => 'Blue',
'birth' => '2948 of the Third Age',
'death' => '3019 of the Third Age (Killed in battle)',
'title' => 'King of Rohan',
'occupation' => 'King',
'affiliation' => 'The Kingdom of Rohan',
'bio' => 'Théoden was the King of Rohan during the War of the Ring. Initially under the influence of Sarumans magic, Théoden was restored to his full strength and vigor by Gandalf. As king, he led the Riders of Rohan into battle at Helms Deep and the Battle of the Pelennor Fields, playing a key role in the defeat of Saurons forces. Despite his valor, Théoden died in the battle at the gates of Minas Tirith, but his legacy lived on through his son Éomer.',
'image_url' => 'https://vignette.wikia.nocookie.net/lotr/images/e/e1/Theoden.png/revision/latest/scale-to-width-down/350?cb=20190707163430',
'youtube_url' => 'https://www.youtube.com/watch?v=ykZlfPXTf7g'
],
[
'name' => 'Éomer',
'species' => 'Human',
'height' => '6\'0" (1.83m)',
'hair' => 'Blonde',
'eyes' => 'Blue',
'birth' => '2991 of the Third Age',
'death' => 'Unknown, likely still alive in the Fourth Age',
'title' => 'King of Rohan',
'occupation' => 'King, Rider of Rohan',
'affiliation' => 'The Kingdom of Rohan',
'bio' => 'Éomer was the nephew of Théoden and the son of Éomund. A brave and skilled warrior, he was instrumental in the defense of Rohan during the War of the Ring. He led the Riders of Rohan in the Battle of Helms Deep and the Battle of the Pelennor Fields, where his forces helped turn the tide in favor of the Free Peoples. After the death of his uncle, Théoden, Éomer became King of Rohan and helped guide the kingdom into a new era of prosperity.',
'image_url' => 'https://vignette.wikia.nocookie.net/lotr/images/3/3f/Éomer.png/revision/latest/scale-to-width-down/350?cb=20190707163551',
'youtube_url' => 'https://www.youtube.com/watch?v=s5qGzysfjoE'
],
[
'name' => 'Faramir',
'species' => 'Human',
'height' => '5\'10" (1.78m)',
'hair' => 'Brown',
'eyes' => 'Grey',
'birth' => '2983 of the Third Age',
'death' => 'Unknown, likely still alive in the Fourth Age',
'title' => 'Captain of Gondor',
'occupation' => 'Soldier, Ranger',
'affiliation' => 'The Kingdom of Gondor',
'bio' => 'Faramir was the younger brother of Boromir and the son of Denethor II, Steward of Gondor. As Captain of Gondors Rangers, he led the defense of Ithilien against the forces of Sauron. Faramir was a wise and honorable man, contrasting with his brother Boromirs more impulsive nature. He helped Frodo and Sam on their journey to destroy the One Ring and refused to take the Ring for himself, showing the strength of his character. After the War of the Ring, Faramir became the Steward of Gondor and married Éowyn of Rohan.',
'image_url' => 'https://static.wikia.nocookie.net/lotr/images/4/43/Faramir.jpg/revision/latest?cb=20071211235438',
'youtube_url' => 'https://www.youtube.com/embed/ZSlRqLu1gcs'
],
[
'name' => 'Éowyn',
'species' => 'Human',
'height' => '5\'7" (1.70m)',
'hair' => 'Blonde',
'eyes' => 'Blue',
'birth' => '2995 of the Third Age',
'death' => 'Unknown, likely still alive in the Fourth Age',
'title' => 'Lady of Rohan',
'occupation' => 'Shieldmaiden, Queen',
'affiliation' => 'The Kingdom of Rohan',
'bio' => 'Éowyn was the niece of King Théoden and the sister of Éomer. She was a courageous and skilled fighter, defying the traditional role of women in her society. Her most notable moment came when she disguised herself as a man to fight in the Battle of the Pelennor Fields, where she slew the Witch-king of Angmar, the Lord of the Nazgûl. After the War of the Ring, she married Faramir, and they ruled Gondor together. Her journey was one of self-discovery, from being trapped by societal expectations to finding her true calling.',
'image_url' => 'https://vignette.wikia.nocookie.net/lotr/images/c/c0/Eowyn_2.png/revision/latest/scale-to-width-down/350?cb=20190602142116',
'youtube_url' => 'https://www.youtube.com/watch?v=5-fMhQ_zTr8'
],
[
'name' => 'Gollum (Sméagol)',
'species' => 'Hobbit (Deformed by the Ring)',
'height' => '4\'0" (1.22m)',
'hair' => 'Brown',
'eyes' => 'Yellow',
'birth' => '2430 of the Third Age',
'death' => '3019 of the Third Age (Fell into Mount Doom)',
'title' => 'Gollum',
'occupation' => 'Former Hobbit, Ring-bearer',
'affiliation' => 'None, briefly helped Frodo',
'bio' => 'Sméagol, later known as Gollum, was once a Stoor Hobbit who found the One Ring. The Ring corrupted him, leading to the murder of his friend and the exile of Sméagol. For centuries, Gollum lived a twisted existence, driven by his obsession with the Ring. Throughout the story, Gollum struggled between his two personalities—Sméagol, the more innocent self, and Gollum, the corrupted, selfish creature. He played a key role in the destruction of the Ring when he bit it off Frodos finger but ultimately fell into the fires of Mount Doom with it, ending the Rings reign of terror.',
'image_url' => 'https://vignette.wikia.nocookie.net/lotr/images/4/4f/Gollum_darker.png/revision/latest/scale-to-width-down/350?cb=20190602142125',
'youtube_url' => 'https://www.youtube.com/watch?v=pV9kLg5HEV4'
],
[
'name' => 'Treebeard',
'species' => 'Ent',
'height' => 'Unknown, towering',
'hair' => 'Leaves, moss',
'eyes' => 'Brown, deep',
'birth' => 'Unknown, ancient',
'death' => 'Unknown, possibly still alive',
'title' => 'Guardian of the Forest',
'occupation' => 'Shepherd of the Trees',
'affiliation' => 'The Free Peoples of Middle-earth',
'bio' => 'Treebeard is one of the ancient Ents, guardians of the forests in Middle-earth. He is the oldest of his kind, and he represents the last of the Ents who have remained true to their mission. He initially hesitated to take action against Saruman, but after witnessing the devastation of his forest, he led the Ents in an assault on Isengard. Treebeards wise and ancient nature was crucial in turning the tide of the war, as his Ents laid waste to Sarumans fortress. He later returned to his forests, where he continues to watch over the worlds trees.',
'image_url' => 'https://vignette.wikia.nocookie.net/lotr/images/4/4a/Treebeard.png/revision/latest/scale-to-width-down/350?cb=20190602142134',
'youtube_url' => 'https://www.youtube.com/watch?v=Asxq6zT8QnA'
],
[
'name' => 'Radagast the Brown',
'species' => 'Maia (Spirit)',
'height' => 'Unknown',
'hair' => 'Brown',
'eyes' => 'Brown',
'birth' => 'Uncertain, an ancient Maia spirit',
'death' => 'Unknown',
'title' => 'Radagast the Brown',
'occupation' => 'Wizard, Guardian of Nature',
'affiliation' => 'The Free Peoples of Middle-earth',
'bio' => 'Radagast the Brown is one of the five Istari sent by the Valar to Middle-earth. Unlike Gandalf and Saruman, Radagast focused on the study and protection of nature, particularly animals and plants. He was a recluse, living in the forests and mountains of Rohan. Though not as prominent in the War of the Ring, Radagast played a supporting role, especially in his connection with the animals and creatures of Middle-earth. His gentle nature and love for wildlife made him a quieter, more peaceful figure compared to other wizards.',
'image_url' => 'https://vignette.wikia.nocookie.net/lotr/images/1/1d/Radagast_the_Brown.png/revision/latest/scale-to-width-down/350?cb=20190602142205',
'youtube_url' => 'https://www.youtube.com/watch?v=Fb6DTlWGG7A'
],
[
'name' => 'Glorfindel',
'species' => 'Elf',
'height' => '6\'0" (1.83m)',
'hair' => 'Blonde',
'eyes' => 'Grey',
'birth' => 'First Age',
'death' => 'Unknown, likely still alive in the Fourth Age',
'title' => 'Lord of Rivendell',
'occupation' => 'Warrior, Lord of Rivendell',
'affiliation' => 'The Free Peoples of Middle-earth',
'bio' => 'Glorfindel is an ancient and noble Elf who played an instrumental role in both the First and Third Ages of Middle-earth. He fought in the Battle of Gondolin during the First Age and was resurrected after dying in battle, embodying the Elven resilience. In the Third Age, Glorfindel returned to Middle-earth and played a significant role in aiding the Fellowship, particularly by escorting Frodo from the Shire to Rivendell. His courage and nobility were evident in all his actions, and he was one of the few Elves who did not sail to the Undying Lands after the Rings destruction.',
'image_url' => 'https://vignette.wikia.nocookie.net/lotr/images/7/7d/Glorfindel.png/revision/latest/scale-to-width-down/350?cb=20190602142217',
'youtube_url' => 'https://www.youtube.com/watch?v=4r7ntxaHE9o'
],
[
'name' => 'Denethor II',
'species' => 'Human',
'height' => '5\'11" (1.80m)',
'hair' => 'Black',
'eyes' => 'Grey',
'birth' => '2930 of the Third Age',
'death' => '3019 of the Third Age (Suicide by Fire)',
'title' => 'Steward of Gondor',
'occupation' => 'Steward of Gondor',
'affiliation' => 'The Kingdom of Gondor',
'bio' => 'Denethor II was the 26th Steward of Gondor, serving in a time of great crisis. Although he was a skilled and capable ruler at times, Denethors obsession with protecting Gondor from Saurons threat, combined with his growing paranoia and despair, led to his tragic downfall. He was manipulated by the Palantír and lost all hope when he believed his son Boromir was dead. Ultimately, Denethors mental state deteriorated, and he perished by his own hand, setting fire to himself in an act of despair.',
'image_url' => 'https://vignette.wikia.nocookie.net/lotr/images/1/1d/Denethor.png/revision/latest/scale-to-width-down/350?cb=20190602142111',
'youtube_url' => 'https://www.youtube.com/watch?v=CU6TByLVR6k'
],
[
'name' => 'Éomer',
'species' => 'Human',
'height' => '6\'0" (1.83m)',
'hair' => 'Blonde',
'eyes' => 'Blue',
'birth' => '2991 of the Third Age',
'death' => 'Unknown, likely still alive in the Fourth Age',
'title' => 'King of Rohan',
'occupation' => 'King, Rider of Rohan',
'affiliation' => 'The Kingdom of Rohan',
'bio' => 'Éomer was the nephew of Théoden and the son of Éomund. A brave and skilled warrior, he was instrumental in the defense of Rohan during the War of the Ring. He led the Riders of Rohan in the Battle of Helms Deep and the Battle of the Pelennor Fields, where his forces helped turn the tide in favor of the Free Peoples. After the death of his uncle, Théoden, Éomer became King of Rohan and helped guide the kingdom into a new era of prosperity.',
'image_url' => 'https://vignette.wikia.nocookie.net/lotr/images/3/3f/Éomer.png/revision/latest/scale-to-width-down/350?cb=20190707163551',
'youtube_url' => 'https://www.youtube.com/watch?v=s5qGzysfjoE'
],
[
'name' => 'Haldir',
'species' => 'Elf',
'height' => '6\'2" (1.88m)',
'hair' => 'Blonde',
'eyes' => 'Grey',
'birth' => 'Unknown, ancient',
'death' => '3019 of the Third Age (Killed in the Battle of Helm\'s Deep)',
'title' => 'Marchwarden of Lothlórien',
'occupation' => 'Elf Warrior, Guard of Lothlórien',
'affiliation' => 'Lothlórien, The Free Peoples of Middle-earth',
'bio' => 'Haldir was a high-ranking Elven warrior from Lothlórien and the Marchwarden of the realm, responsible for guarding the borders of the woodland kingdom. He appeared in *The Two Towers* to lead an Elven force to the defense of Helms Deep, forming an unlikely alliance between the Elves and the Men of Rohan. Though his death in battle was brief, his valiant sacrifice and support of the Free Peoples in their time of need left a lasting impression.',
'image_url' => 'https://vignette.wikia.nocookie.net/lotr/images/5/50/Haldir.png/revision/latest/scale-to-width-down/350?cb=20190602142155',
'youtube_url' => 'https://www.youtube.com/watch?v=2rpjH9ZWLg4'
],
[
'name' => 'The Witch-king of Angmar',
'species' => 'Ringwraith (Human)',
'height' => '7\'0" (2.13m)',
'hair' => 'None (Faceless)',
'eyes' => 'Red (Glowing)',
'birth' => 'Unknown, 1000s of years ago',
'death' => '3019 of the Third Age (Killed by Éowyn)',
'title' => 'Lord of the Nazgûl',
'occupation' => 'Servant of Sauron',
'affiliation' => 'Sauron, The Nazgûl',
'bio' => 'The Witch-king of Angmar was the most powerful of the Nazgûl, Saurons terrifying ringwraiths. Once a King of Men, he was corrupted by the power of the One Ring, becoming a servant of Sauron. He led the forces of Mordor in numerous campaigns, including the conquest of Gondor and the destruction of Arnor. The Witch-king was a fearsome presence on the battlefield, but he met his end in the Battle of the Pelennor Fields, where he was defeated by Éowyn and Merry, fulfilling the prophecy that no man could kill him.',
'image_url' => 'https://vignette.wikia.nocookie.net/lotr/images/9/9e/Witch-king.png/revision/latest/scale-to-width-down/350?cb=20190602142112',
'youtube_url' => 'https://www.youtube.com/watch?v=rKL8FgZzm7o'
],
[
'name' => 'Gothmog (Lieutenant of Morgul)',
'species' => 'Orc',
'height' => '7\'0" (2.13m)',
'hair' => 'None (Pale, Corpse-like)',
'eyes' => 'Red',
'birth' => 'Unknown',
'death' => '3019 of the Third Age (Killed in the Battle of the Black Gate)',
'title' => 'Lieutenant of Mordor',
'occupation' => 'Commander of the Orcs',
'affiliation' => 'Sauron, Mordor',
'bio' => 'Gothmog was the Lieutenant of Morgul and a high-ranking commander of Saurons forces in the War of the Ring. As one of the more prominent Orc leaders, he was present during the Battle of the Pelennor Fields, leading the forces of Mordor. Gothmogs grotesque appearance and ruthlessness made him a terrifying figure. He met his end in the Battle of the Black Gate, where his forces were destroyed and he himself was slain by the armies of Gondor and Rohan.',
'image_url' => 'https://vignette.wikia.nocookie.net/lotr/images/9/94/Gothmog_Lieutenant_of_Morgul.png/revision/latest/scale-to-width-down/350?cb=20190602142219',
'youtube_url' => 'https://www.youtube.com/watch?v=hegeHfK5Dh4'
]
];
return $characters;
}
}

View File

@ -0,0 +1,21 @@
<?php
namespace Drupal\dc_core\Controller;
use Drupal\dc_core\Attributes\LotrCharacterList;
use Drupal\Core\Controller\ControllerBase;
use Drupal\Core\Cache\CacheableJsonResponse;
use Symfony\Component\HttpFoundation\Response;
final class LotrCharacters extends ControllerBase {
use LotrCharacterList;
public function characterJson(): Response {
/* return new Response(json_encode( */
/* $this->characterList, */
/* JSON_PRETTY_PRINT, JSON_UNESCAPED_SLASHES */
/* )); */
return new CacheableJsonResponse($this->characterList);
}
}

View File

@ -0,0 +1,52 @@
<?php
namespace Drupal\dc_core\Drush\Commands;
use Drush\Commands\DrushCommands;
use Drush\Attributes as CLI;
final class CharacterImport extends DrushCommands {
/**
* Imports characters from Lord of the Rings.
*/
#[CLI\Command(name: 'lotr:character-import', aliases: ['lotr-i'])]
#[CLI\Usage(name: 'drush lotr-i', description: 'Adds update operations to queue for import.')]
public function importCharacters(): void {
$http_client = \Drupal::httpClient();
$character_endpoint = "https://dchadwick.ddev.site/api/character-list";
$data = $http_client->get($character_endpoint)->getBody()->getContents();
$json_data = json_decode($data, TRUE);
// Create the queue.
$character_import_queue = \Drupal::queue('character_import');
foreach ($json_data as $id => $api_character) {
// Load corresponding Drupal entity, check last modified.
$properties = [
'field_character_id' => $id,
];
$drupal_entity = \Drupal::entityTypeManager()
->getStorage('node')
->loadByProperties($properties);
if (empty($drupal_entity)) {
$character = new \stdClass();
$character->id = $id;
$character->operation = "CREATE";
$character_import_queue->createItem($character);
}
else {
$drupal_entity = reset($drupal_entity);
$changed = $drupal_entity->getChangedTime();
if ($changed < $api_character['last_modified']) {
$character = new \stdClass();
$character->id = $id;
$character->operation = "UPDATE";
$character_import_queue->createItem($character);
};
}
}
}
}

View File

@ -0,0 +1,162 @@
<?php
namespace Drupal\dc_core\Plugin\QueueWorker;
use Drupal\Core\Annotation\QueueWorker;
use Drupal\Core\Database\Connection;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
use Drupal\Core\Queue\QueueWorkerBase;
use Symfony\Component\DependencyInjection\ContainerInterface;
/**
* Custom Queue Worker.
*
* @QueueWorker(
* id = "character_import",
* title = @Translation("Character Import Queue"),
* cron = {"time" = 60}
* )
*/
final class CharacterQueueWorker extends QueueWorkerBase implements ContainerFactoryPluginInterface {
/**
* The entity type manager.
*
* @var \Drupal\Core\Entity\EntityTypeManagerInterface
*/
protected $entityTypeManager;
/**
* The database connection.
*
* @var \Drupal\Core\Database\Connection
*/
protected $database;
/**
* Main constructor.
*
* @param array $configuration
* Configuration array.
* @param mixed $plugin_id
* The plugin id.
* @param mixed $plugin_definition
* The plugin definition.
* @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
* The entity type manager.
* @param \Drupal\Core\Database\Connection $database
* The connection to the database.
*/
public function __construct(
array $configuration,
$plugin_id,
$plugin_definition,
EntityTypeManagerInterface $entity_type_manager,
Connection $database
) {
parent::__construct($configuration, $plugin_id, $plugin_definition);
$this->entityTypeManager = $entity_type_manager;
$this->database = $database;
}
/**
* Used to grab functionality from the container.
*
* @param \Symfony\Component\DependencyInjection\ContainerInterface $container
* The container.
* @param array $configuration
* Configuration array.
* @param mixed $plugin_id
* The plugin id.
* @param mixed $plugin_definition
* The plugin definition.
* @return static
*/
public static function create(
ContainerInterface $container,
array $configuration,
$plugin_id,
$plugin_definition
) {
return new static(
$configuration,
$plugin_id,
$plugin_definition,
$container->get('entity_type.manager'),
$container->get('database'),
);
}
/**
* Processes an item in the queue.
*
* @param mixed $data
* The queue item data.
*
* @throws \Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException
* @throws \Drupal\Component\Plugin\Exception\PluginNotFoundException
* @throws \Drupal\Core\Entity\EntityStorageException
* @throws \Exception
*/
public function processItem($data) {
$client = \Drupal::httpClient();
$url = "https://dchadwick.ddev.site/api/character-list";
$character_api_data = $client->request('GET', $url, ['verify' => false])->getBody()->getContents();
$json_data = json_decode($character_api_data, TRUE);
$target_data = $json_data[$data->id];
if ($data->operation == "CREATE") {
$node_values = [
'type' => 'character',
'title' => $target_data['name'],
'field_species' => $target_data['species'],
'field_character_height' => $target_data['height'],
'field_hair' => $target_data['hair'],
'field_eyes' => $target_data['eyes'],
'field_birth' => $target_data['birth'],
'field_death' => $target_data['death'],
'field_character_title' => $target_data['title'],
'field_occupation' => $target_data['occupation'],
'field_affiliation' => $target_data['affiliation'],
'field_bio' => ['value' => $target_data['bio']],
'field_character_image' => $target_data['image_url'],
'field_character_id' => $data->id,
'field_youtube_url' => $target_data['youtube_url'],
];
$node = \Drupal::entityTypeManager()->getStorage('node')->create($node_values)->save();
\Drupal::logger('dc_core')->notice("Created character " . $target_data['name']);
}
elseif ($data->operation == "UPDATE") {
// load the entity by character id.
$existing_entity = $this->entityTypeManager->getStorage('node')->loadByProperties([
'type' => 'character',
'field_character_id' => $data->id,
]);
$existing_entity = reset($existing_entity);
$node_values = [
'title' => $target_data['name'],
'field_species' => $target_data['species'],
'field_character_height' => $target_data['height'],
'field_hair' => $target_data['hair'],
'field_eyes' => $target_data['eyes'],
'field_birth' => $target_data['birth'],
'field_death' => $target_data['death'],
'field_character_title' => $target_data['title'],
'field_occupation' => $target_data['occupation'],
'field_affiliation' => $target_data['affiliation'],
'field_bio' => ['value' => $target_data['bio']],
'field_character_image' => $target_data['image_url'],
'field_character_id' => $data->id,
'field_youtube_url' => $target_data['youtube_url'],
];
foreach ($node_values as $field_name => $value) {
$existing_entity->set($field_name, $value);
}
$existing_entity->save();
\Drupal::logger('dc_core')->notice("Updated character " . $target_data['name']);
}
}
}

View File

@ -0,0 +1,55 @@
<?php
namespace Drupal\Tests\dc_core\Functional;
use Drupal\Tests\dc_core\Functional\DrupalUiBase;
use Symfony\Component\Process\Process;
use Drupal\Core\Config\FileStorage;
/**
* Tests that the Rules UI pages are reachable.
*
* @group rules_ui
*/
class LotrTests extends DrupalUiBase {
/**
* Modules to enable.
*
* @var array
*/
protected static $modules = [
'node',
'dc_core',
];
/**
* Theme to enable.
*
* @var string
*/
protected $defaultTheme = 'dchadwick';
protected $adminUser;
/**
* {@inheritdoc}
*/
protected function setUp(): void {
parent::setUp();
}
public function testSite200() {
$this->drupalGet('<front>');
$this->assertSession()->statusCodeEquals(200);
}
public function testControllerData() {
$this->drupalGet("api/character-list");
$session = $this->assertSession();
$session->statusCodeEquals(200);
$session->responseHeaderEquals('Content-Type', 'application/json');
$session->pageTextContains("Frodo Baggins");
}
}

View File

@ -2,37 +2,166 @@
namespace Drupal\ufc\Commands;
use Drupal\ufc\Services\FighterImporter;
use Drupal\ufc\Services\FightImporter;
use Drupal\Core\Batch\BatchBuilder;
use Drupal\node\Entity\Node;
use Drush\Commands\DrushCommands;
use Drush\Attributes as CLI;
use Symfony\Component\DomCrawler\Crawler;
class UfcCommands extends DrushCommands {
protected $cacheId = 'ufc:fighter-list';
/**
* Import fighters from UFC.com.
*/
#[CLI\Command(name: 'ufc:import-fighters', aliases: ['impft'])]
public function importFighters(): void {
// Fighter importer service.
$fighter_importer = \Drupal::service('ufc.import_fighters');
// First check for the item in cache.
$fighter_list = \Drupal::cache()->get($this->cacheId);
if (!$fighter_list) {
$fighter_list = $fighter_importer->getListOfCurrentFighters();
\Drupal::cache()->set($this->cacheId, $fighter_list, time() + 86400);
}
else {
$fighter_list = $fighter_list->data;
}
// Add each division to a batch process.
$batch = new BatchBuilder();
$batch->setTitle("Starting Complete Fighter Import")
->setFinishCallback([UfcCommands::class, 'importFinished'])
->setInitMessage("Importing...");
foreach ($fighter_list as $division => $fighters) {
$args = [
$division,
$fighters,
];
$batch->addOperation([FighterImporter::class, 'processDivision'], $args);
}
// Set and run the batch.
batch_set($batch->toArray());
drush_backend_batch_process();
}
/**
* Import events based on ESPN.com.
*/
#[CLI\Command(name: 'ufc:import-events', aliases: ['impev'])]
public function importEvents(): void {
$fight_importer = \Drupal::service("ufc.import_fights");
$event_list = [];
$events_base= "https://www.espn.com/mma/schedule/_/year/";
$event_base = "https://www.espn.com";
// Old fashioned for loop to target years.
for ($i = 2000; $i <= 2025; $i++) {
$year_event_url = $events_base . "{$i}/league/ufc";
$event_listing = \Drupal::httpClient()
->get($year_event_url)->getBody()->getContents();
$crawler = new Crawler($event_listing);
$events = $crawler->filter('.Schedule__EventLeague--ufc tbody tr');
foreach ($events as $event) {
$event_list[$i][] = $event->ownerDocument->saveHTML($event);
}
}
// Add each division to a batch process.
$batch = new BatchBuilder();
$batch->setTitle("Starting Event Import")
->setFinishCallback([UfcCommands::class, 'eventImportFinished'])
->setInitMessage("Importing events...");
foreach ($event_list as $year => $events) {
foreach ($events as $event) {
$args = [
$event,
$year,
];
$batch->addOperation([FightImporter::class, 'processEvent'], $args);
}
}
// Set and run the batch.
batch_set($batch->toArray());
drush_backend_batch_process();
}
/**
* Update fights with their event date.
*
* @command ufc:update-fight-dates
* @aliases ufc-ufd
*/
public function updateFightDates() {
#[CLI\Command(name: 'ufc:update-fight-dates', aliases: ['ufd'])]
public function updateFightDates(): void {
// Get all fights
// For each fight
// Go get event date.
// Add to new field
// Save.
$fights = \Drupal::entityTypeManager()->getStorage('node')->loadByProperties(['type' => 'fight']);
// Add each division to a batch process.
$batch = new BatchBuilder();
$batch->setTitle("Starting Fight Update")
->setFinishCallback([UfcCommands::class, 'eventImportFinished'])
->setInitMessage("Importing events...");
foreach ($fights as $fight) {
$fight->field_fight_date = $this->getEventDateTimestampFromFight($fight);
if ($fight->save()) {
$this->output->writeln($fight->title->value . " updated successfully.");
}
else {
$this->output->writeln($fight->title->value . " failed.");
}
$args = [
$fight,
];
$batch->addOperation([UfcCommands::class, 'updateFight'], $args);
}
// Set and run the batch.
batch_set($batch->toArray());
drush_backend_batch_process();
}
public static function updateFight($fight, $context) {
$fight->field_fight_date = [UfcCommands::class, 'getEventDateTimestampFromFight', $fight];
if ($fight->save()) {
\Drupal::messenger()->addMessage($fight->title->value . " updated successfully.");
}
else {
\Drupal::messenger()->addMessage($fight->title->value . " failed.");
}
}
/**
* Create Fights.
*/
#[CLI\Command(name: 'ufc:create-fights', aliases: ['cf'])]
public function createUfcFights(): void {
$existing_fights = \Drupal::entityTypeManager()->getStorage('node')->loadByProperties(['type' => 'fight']);
foreach ($existing_fights as $existing_fight) {
$delete = $existing_fight->delete();
if ($delete) {
\Drupal::logger('ufc')->notice("Removed " . $existing_fight->getTitle());
}
}
// Get all events - add each to queue, fights created per event.
$events = \Drupal::entityTypeManager()->getStorage('taxonomy_term')->loadByProperties(['vid' => 'ufc_events']);
// Add each division to a batch process.
$batch = new BatchBuilder();
$batch->setTitle("Creating fights in batches....")
->setFinishCallback([UfcCommands::class, 'importFinished'])
->setInitMessage("Processing");
foreach ($events as $event) {
if ($event->field_event_url->uri == '/mma/fightcenter/_/id/600037492/league/ufc') {
continue;
}
$args = [
$event,
];
$batch->addOperation([FightImporter::class, 'createFightsByEvent'], $args);
}
// Set and run the batch.
batch_set($batch->toArray());
drush_backend_batch_process();
}
private function getEventDateTimestampFromFight(Node $fight_node) {
/**
* Gets the event date as a timestamp.
*/
private function getEventDateTimestampFromFight(Node $fight_node): int|bool {
// Get field value.
$event_date_value = $fight_node->field_event->entity->field_event_date->value;
assert($event_date_value, !null);
@ -40,4 +169,40 @@ private function getEventDateTimestampFromFight(Node $fight_node) {
return strtotime($event_date_value);
}
/**
* Handle batch completion.
*
* @param bool $success
* TRUE if all batch API tasks were completed successfully.
* @param array $results
* An results array from the batch processing operations.
* @param array $operations
* A list of the operations that had not been completed.
* @param string $elapsed
* Batch.inc kindly provides the elapsed processing time in seconds.
*/
public static function importFinished(bool $success, array $results, array $operations, string $elapsed): void {
// Finish the batch here.
$message = "Processed " . $results['processed'] . " divisions.";
\Drupal::messenger()->addMessage($message);
}
/**
* Handle batch completion.
*
* @param bool $success
* TRUE if all batch API tasks were completed successfully.
* @param array $results
* An results array from the batch processing operations.
* @param array $operations
* A list of the operations that had not been completed.
* @param string $elapsed
* Batch.inc kindly provides the elapsed processing time in seconds.
*/
public static function eventImportFinished(bool $success, array $results, array $operations, string $elapsed): void {
// Finish the batch here.
$message = "Processed " . $results['processed'] . " events.";
\Drupal::messenger()->addMessage($message);
}
}

View File

@ -7,6 +7,7 @@
use Drupal\taxonomy\Entity\Term;
use Drupal\node\Entity\Node;
use GuzzleHttp\Client;
use GuzzleHttp\Exception\RequestException;
use Symfony\Component\DomCrawler\Crawler;
class FightImporter {
@ -56,9 +57,9 @@ public function __construct(
*/
public function importEvents(): void {
// First delete all events :-).
$this->removeExistingEvents();
/* $this->removeExistingEvents(); */
// Old fashioned for loop to target years.
for ($i = 2000; $i <= 2024; $i++) {
for ($i = 2011; $i <= 2025; $i++) {
$year_event_url = self::EVENTS_BASE . "{$i}/league/ufc";
$event_listing = $this->httpClient
->get($year_event_url)->getBody()->getContents();
@ -83,7 +84,10 @@ public function importEvents(): void {
}
}
private function processEvent(\DOMElement $event, string $year): array {
/**
* Process an event into the system.
*/
public static function processEvent(\DOMElement $event, string $year): array {
if ($event->childElementCount !== 4) {
return [];
}
@ -92,7 +96,8 @@ private function processEvent(\DOMElement $event, string $year): array {
];
for ($i = 0; $i < 4; $i++) {
if ($i === 0) {
$event_date = $this->convertDate($event->childNodes[0]->textContent . " $year");
$date_str = $event->childNodes[0]->textContent . " $year";
$event_date = \Drupal::service('date.formatter')->format(strtotime($date_str), 'custom', 'Y-m-d');
$term_build['field_event_date'] = $event_date;
}
if ($i === 1) {
@ -156,32 +161,25 @@ private function removeExistingEvents(): void {
/**
* Create fights from events.
*/
public function createFights(): void {
// Clear out past fights.
$existing_fights = $this->entityTypeManager->getStorage('node')->loadByProperties(['type' => 'fight']);
foreach ($existing_fights as $existing_fight) {
$delete = $existing_fight->delete();
if ($delete) {
\Drupal::logger('ufc')->notice("Removed " . $existing_fight->getTitle());
}
}
// Go get all events.
$all_events = $this->entityTypeManager->getStorage('taxonomy_term')
->loadByProperties(['vid' => 'ufc_events']);
foreach ($all_events as $event) {
$event_page_html = $this->httpClient
public static function createFightsByEvent($event, $context): void {
try {
$event_page_html = \Drupal::httpClient()
->get(self::EVENT_BASE . $event->field_event_url->uri)
->getBody()->getContents();
$crawler = new Crawler($event_page_html);
$fight_result_rows = $crawler->filter(".MMAGamestrip");
foreach ($fight_result_rows as $fight_result_row) {
$result = $this->processFightResultRow($fight_result_row);
$result = \Drupal::service('ufc.import_fights')->processFightResultRow($fight_result_row);
if (empty($result)) {
continue;
}
$result['event'] = $event->id();
$this->createFightNodeFromResult($result);
\Drupal::service('ufc.import_fights')->createFightNodeFromResult($result);
}
$context['results']['processed']++;
} catch (RequestException $e) {
$context['results']['failed']++;
dump($e->getMessage());
}
}
@ -236,7 +234,7 @@ private function getFighterIdByName(string $name): int {
/**
* Iterate over fight result rows to extract results.
*/
private function processFightResultRow(\DOMElement $row): array {
public function processFightResultRow(\DOMElement $row): array {
$results = [
'winner' => 0,
];

View File

@ -98,9 +98,9 @@ public function importFighters(): void {
else {
$fighters_by_div = self::getListOfCurrentFighters();
// Process each fighter into system.
foreach ($fighters_by_div as $division => $fighters) {
$this->processDivision($division, $fighters);
}
/* foreach ($fighters_by_div as $division => $fighters) { */
/* $this->processDivision($division, $fighters); */
/* } */
}
}
/**
@ -109,9 +109,11 @@ public function importFighters(): void {
* @param mixed $div
* @param mixed $fighters
*/
private function processDivision($div, $fighters): void {
public static function processDivision($div, $fighters, &$context): void {
\Drupal::logger('ufc')->notice("Starting to update $div");
foreach ($fighters as $fighter_data) {
$fighter = new Fighter($this->httpClient);
$fighter = new Fighter(\Drupal::httpClient());
$fighter->first_name = $fighter_data['firstname'];
$fighter->last_name = $fighter_data['lastname'];
$fighter->image = $fighter_data['image'];
@ -122,7 +124,7 @@ private function processDivision($div, $fighters): void {
// Check if node exists, by title.
$fighter->createMediaEntityFromImage();
$title = $fighter->first_name . " " . $fighter->last_name;
$node_lookup = reset($this->entityTypeManager->getStorage('node')->loadByProperties(['title' => $title]));
$node_lookup = reset(\Drupal::entityTypeManager()->getStorage('node')->loadByProperties(['title' => $title]));
if (!empty($node_lookup)) {
// Update instead of create.
@ -134,6 +136,7 @@ private function processDivision($div, $fighters): void {
$fighter->createPlayerNode();
}
}
$context['results']['processed']++;
}
/**
@ -157,7 +160,6 @@ public function getListOfCurrentFighters(): array {
* @param string $base_url
*/
public function loopThroughFighterPages($base_url): void {
// Here you are Dan.
// Implement caching to store instead of needing fresh requests.
for ($i=0; $i<=100; $i++) {
$ua = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.4.1 Safari/605.1.15';
@ -165,7 +167,7 @@ public function loopThroughFighterPages($base_url): void {
'referer' => true,
'verify' => false,
'headers' => [
'User-Agent' => 'DC SCRAPER/v1.0',
'User-Agent' => $ua,
'Accept' => 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8',
'Accept-Encoding' => 'gzip, deflate, br',
]

View File

@ -20,10 +20,12 @@ public function setUp(): void {
}
/**
* @dataProvider extractFighterNamesDataProvider
*
*/
public function testExtractFighterNames($test_input) {
$this->assertEquals("1", 2, "These do not match.");
public function testGetCurrentFighters() {
$fighters = $this->fighterImporter->getListOfCurrentFighters();
dump($fighters);
/* $this->assertEquals("1", 2, "These do not match."); */
}
}

View File

@ -545,6 +545,68 @@ table.cols-5 td.incorrect {
right: 34px;
}
#block-dchadwick-breadcrumbs {
background: var(--site-gray);
}
#block-dchadwick-breadcrumbs ol {
max-width: 1300px;
margin: 0 50px;
padding: 10px 0;
list-style: none;
display: flex;
gap: 10px;
}
#block-dchadwick-breadcrumbs ol li:not(:last-child):after {
content: "/";
display: inline-block;
position: relative;
margin-left: 10px;
}
#block-dchadwick-breadcrumbs ol a, #block-dchadwick-breadcrumbs ol li {
color: var(--site-platinum);
font-size: 14px;
}
.node-type-character .layout--twocol-section {
gap: 20px;
}
.node-type-character .layout--twocol-section .layout__region--first {
flex: 0 1 calc(67% - 20px);
}
.node-type-character .layout--twocol-section .layout__region--first h1 {
margin-bottom: 5px;
background: var(--site-primary);
color: var(--site-platinum);
padding: 0 10px;
}
.node-type-character .layout--twocol-section .layout__region--first h3 {
margin: 0;
font-style: italic;
font-size: 16px;
color: var(--site-gray);
display: inline-block;
padding: 0 10px;
}
.node-type-character .layout--twocol-section .layout__region--second {
flex: 0 1 calc(33% - 20px);
text-align: center;
}
.node-type-character .layout--twocol-section .layout__region--second [class^=field] > div:first-child {
background: var(--site-gray);
color: var(--site-white);
font-size: 18px;
font-weight: 900;
padding: 5px 0;
}
.node-type-character .layout--twocol-section .layout__region--second [class^=field] div:nth-child(2) {
padding: 5px 0;
color: var(--site-gray);
}
.node-type-character .layout__region--first p {
font-size: 18px;
line-height: 24px;
}
html {
font-size: 100%;
box-sizing: border-box;

View File

@ -16,9 +16,15 @@ function dchadwick_preprocess_node__article(&$vars) {
$vars['#attached']['library'] = 'dchadwick/articles';
}
function dchadwick_preprocess_field(&$vars) {
if (isset($vars['field_name'])) {
$vars['attributes']['class'][] = $vars['field_name'];
}
}
function dchadwick_page_attachments_alter(&$page) {
// Attach brain.js to all pages? No reason at the moment.
/* $page['#attached']['library'][] = 'dchadwick/brainjs'; */
$page['#attached']['library'][] = 'dchadwick/brainjs';
}
function dchadwick_preprocess_node__fighter(&$vars) {

View File

@ -2,7 +2,7 @@ document.addEventListener('readystatechange', event => {
// When HTML/DOM elements are ready:
if (event.target.readyState === "interactive") { //does same as: ..addEventListener("DOMContentLoaded"..
highlightFightHistory();
let train = false;
let train = true;
if (train) {
setTimeout(() => {
trainTheBrain();
@ -32,9 +32,9 @@ function highlightFightHistory() {
function trainTheBrain() {
const config = {
iterations: 50000,
iterations: 5000,
log: true,
logPeriod: 1000,
logPeriod: 100,
binaryThresh: 0.5,
hiddenLayers: [40, 20], // array of ints for the sizes of the hidden layers in the network
activation: 'sigmoid', // supported activation types: ['sigmoid', 'relu', 'leaky-relu', 'tanh'],

File diff suppressed because it is too large Load Diff

View File

@ -15,8 +15,7 @@
"gulp": "^4.0.2",
"gulp-concat": "^2.6.1",
"gulp-sass": "^5.1.0",
"postcss": "^8.4.47",
"tailwindcss": "^3.4.13"
"postcss": "^8.4.47"
},
"dependencies": {
"sass": "^1.71.1"

Some files were not shown because too many files have changed in this diff Show More