A whole lotta stuff.
This commit is contained in:
313
web/modules/custom/ufc/src/FightPredictor.php
Normal file
313
web/modules/custom/ufc/src/FightPredictor.php
Normal file
@@ -0,0 +1,313 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\ufc;
|
||||
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
use Drupal\ufc\Fighter;
|
||||
use Drupal\node\Entity\Node;
|
||||
use Drupal\Core\Entity\EntityTypeManager;
|
||||
use Drupal\Core\Config\ConfigFactory;
|
||||
|
||||
class FightPredictor {
|
||||
|
||||
/**
|
||||
* First Fighter.
|
||||
*
|
||||
* @var Drupal\node\Entity\Node
|
||||
*/
|
||||
protected $fighterOne;
|
||||
|
||||
/**
|
||||
* Second Fighter.
|
||||
*
|
||||
* @var Drupal\node\Entity\Node
|
||||
*/
|
||||
protected $fighterTwo;
|
||||
|
||||
/**
|
||||
* Entity Type Manager.
|
||||
*
|
||||
* @var Drupal\Core\Entity\EntityTypeManager
|
||||
*/
|
||||
protected $entityTypeManager;
|
||||
|
||||
/**
|
||||
* Config for ufc weights.
|
||||
*
|
||||
* @var Drupal\Core\Config\ConfigFactory
|
||||
*/
|
||||
protected $config;
|
||||
|
||||
/**
|
||||
* Weights config object.
|
||||
*
|
||||
* @var Drupal\Core\Config\ConfigFactory
|
||||
*/
|
||||
protected $weights;
|
||||
|
||||
|
||||
/**
|
||||
* Public constructor.
|
||||
*/
|
||||
public function __construct(EntityTypeManager $entityTypeManager, ConfigFactory $config) {
|
||||
$this->entityTypeManager = $entityTypeManager;
|
||||
$this->config = $config->getEditable('ufc.weights');
|
||||
$this->weights = $config->getEditable('ufc.weights')->get('fight_weights');
|
||||
}
|
||||
|
||||
/**
|
||||
* The results of the fight.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $results = [
|
||||
'fighter_one' => [
|
||||
'name' => null,
|
||||
'points' => 0,
|
||||
'advantages' => [],
|
||||
'disadvantages' => []
|
||||
],
|
||||
'fighter_two' => [
|
||||
'name' => null,
|
||||
'points' => 0,
|
||||
'advantages' => [],
|
||||
'disadvantages' => []
|
||||
],
|
||||
'skips' => 0
|
||||
];
|
||||
|
||||
/**
|
||||
* The amount of categories skipped.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
protected $skipCount;
|
||||
|
||||
/**
|
||||
* Calculate the fight results.
|
||||
*/
|
||||
public function calculate(Node $fighter_one, Node $fighter_two) {
|
||||
// Reset skip count.
|
||||
$this->skipCount = 0;
|
||||
// First Fighter.
|
||||
$this->fighterOne = $fighter_one;
|
||||
// Second Fighter.
|
||||
$this->fighterTwo = $fighter_two;
|
||||
|
||||
// Run the fight.
|
||||
$this->runFight();
|
||||
|
||||
// Label the results array.
|
||||
$this->results['fighter_one']['name'] = $fighter_one->label();
|
||||
$this->results['fighter_two']['name'] = $fighter_two->label();
|
||||
// Add total skips.
|
||||
$this->results['skips'] = $this->skipCount;
|
||||
|
||||
// echo "<pre>";
|
||||
// print_r($this->results);
|
||||
// echo "</pre>";
|
||||
// exit();
|
||||
|
||||
return $this->results;
|
||||
}
|
||||
|
||||
/**
|
||||
* Populate fight results.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function runFight() {
|
||||
$points = 0;
|
||||
$this->calcComparativePoints();
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate comparative points.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function calcComparativePoints() {
|
||||
$this->calculateDiff('field_height', 'height');
|
||||
$this->calculateDiff('field_weight', 'weight');
|
||||
$this->calculateDiff('field_age', 'age');
|
||||
$this->calculateDiff('field_reach', 'reach');
|
||||
$this->calculateDiff('field_leg_reach', 'leg_reach');
|
||||
$this->calculateDiff('field_wins', 'wins');
|
||||
$this->calculateDiff('field_losses', 'losses', TRUE);
|
||||
$this->calculateDiff('field_ties', 'ties');
|
||||
$this->calculateDiff('field_decisions', 'decisions');
|
||||
$this->calculateDiff('field_knockouts', 'knockouts');
|
||||
$this->calculateDiff('field_submissions', 'submissions');
|
||||
$this->calculateDiff('field_grappling_accuracy', 'grappling_accuracy');
|
||||
$this->calculateDiff('field_striking_accuracy', 'striking_accuracy');
|
||||
$this->calculateDiff('field_strikes_per_minute', 'strikes_per_minute');
|
||||
$this->calculateDiff('field_absorbed_per_min', 'absorbed_per_min', TRUE);
|
||||
$this->calculateDiff('field_takedowns_per_15', 'takedowns_per_15');
|
||||
$this->calculateDiff('field_knockdown_ratio', 'knockdown_ratio');
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate the weighted diff between two fighters.
|
||||
*
|
||||
* @param [type] $field
|
||||
* @param [type] $weight_label
|
||||
* @return void
|
||||
*/
|
||||
public function calculateDiff($field, $weight_label, $inverse = FALSE) {
|
||||
$f1 = $this->getFieldValue($field, $this->fighterOne);
|
||||
$f2 = $this->getFieldValue($field, $this->fighterTwo);
|
||||
|
||||
if (empty($f1) || empty($f2)) {
|
||||
$this->skipCount += 1;
|
||||
return;
|
||||
}
|
||||
|
||||
$weighted_points = 1 * $this->config->get('fight_weights')[$weight_label];
|
||||
|
||||
if ($f1 === $f2) {
|
||||
$this->skipCount += 1;
|
||||
return;
|
||||
}
|
||||
|
||||
if ($inverse) {
|
||||
if ($f1 < $f2) {
|
||||
$this->results['fighter_one']['points'] += $weighted_points;
|
||||
$this->results['fighter_one']['advantages'][] = $field;
|
||||
$this->results['fighter_two']['disadvantages'][] = $field;
|
||||
return;
|
||||
}
|
||||
elseif ($f1 > $f2) {
|
||||
$this->results['fighter_two']['points'] += $$weighted_points;
|
||||
$this->results['fighter_two']['advantages'][] = $field;
|
||||
$this->results['fighter_one']['disadvantages'][] = $field;
|
||||
return;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if ($f1 > $f2) {
|
||||
$this->results['fighter_one']['points'] += $weighted_points;
|
||||
$this->results['fighter_one']['advantages'][] = $field;
|
||||
$this->results['fighter_two']['disadvantages'][] = $field;
|
||||
}
|
||||
elseif ($f1 < $f2) {
|
||||
$this->results['fighter_two']['points'] += $weighted_points;
|
||||
$this->results['fighter_two']['advantages'][] = $field;
|
||||
$this->results['fighter_one']['disadvantages'][] = $field;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get value from a field.
|
||||
*/
|
||||
public function getFieldValue($field, Node $fighter) {
|
||||
$field_values = reset($fighter->get($field)->getValue());
|
||||
|
||||
if (empty($field_values['value'])) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return (float) $field_values['value'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate the knockout percentage for a fighter.
|
||||
*
|
||||
* @param Node $fighter
|
||||
* @return void
|
||||
*/
|
||||
public function getKnockoutPercentage(Node $fighter) {
|
||||
|
||||
$total_fights =
|
||||
$this->getFieldValue('field_wins', $fighter) +
|
||||
$this->getFieldValue('field_losses', $fighter) +
|
||||
$this->getFieldValue('field_ties', $fighter);
|
||||
|
||||
$knockout_pct = $this->getFieldValue('field_knockouts', $fighter) / $total_fights;
|
||||
|
||||
return $knockout_pct;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update predictions for all fights in batches
|
||||
*/
|
||||
public function updatePredictionsBatched($fights, &$context) {
|
||||
// $fights = $this->entityTypeManager->getStorage('node')->loadByProperties(['type' => 'fight']);
|
||||
$results = [];
|
||||
foreach ($fights as $fight) {
|
||||
\Drupal::logger('ufc')->notice("Starting " . $fight->label() . "");
|
||||
$fight->save();
|
||||
$results[] = $fight->id();
|
||||
}
|
||||
$context['results'] = $results;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update predictions for all fights.
|
||||
*/
|
||||
public function updatePredictions() {
|
||||
$fights = $this->entityTypeManager->getStorage('node')->loadByProperties(['type' => 'fight']);
|
||||
|
||||
// $count = 0;
|
||||
|
||||
foreach ($fights as $fight) {
|
||||
\Drupal::logger('ufc')->notice("Starting " . $fight->label() . "");
|
||||
$fight->save();
|
||||
|
||||
// if ($count == 4) {
|
||||
// return;
|
||||
// }
|
||||
// $count++;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public function adjustWeights($adv, $dis_adv) {
|
||||
foreach ($adv as $cat_to_increase) {
|
||||
$clean = str_replace('field_', '', $cat_to_increase);
|
||||
$this->adjustWeight($clean, 2);
|
||||
}
|
||||
|
||||
foreach ($dis_adv as $cat_to_decrease) {
|
||||
$clean = str_replace('field_', '', $cat_to_decrease);
|
||||
$this->adjustWeight($clean, -1);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function to increase the weight of a category.
|
||||
*/
|
||||
public function adjustWeight($key, $increment) {
|
||||
$current_val = $this->config->get('fight_weights')[$key];
|
||||
$increase = $current_val + $increment;
|
||||
$target = 'fight_weights.' . $key;
|
||||
$this->config->set($target, $increase)->save();
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function to reset all weighting.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function resetWeights() {
|
||||
foreach ($this->config->get('fight_weights') as $cat => $weight) {
|
||||
$this->config->set('fight_weights.' . $cat, 1)->save();
|
||||
}
|
||||
}
|
||||
|
||||
public function fightUpdatedCallback($success, $results, $operations) {
|
||||
// The 'success' parameter means no fatal PHP errors were detected. All
|
||||
// other error management should be handled using 'results'.
|
||||
if ($success) {
|
||||
$message = \Drupal::translation()->formatPlural(
|
||||
count($results),
|
||||
'One fight processed.', '@count fight processed.'
|
||||
);
|
||||
}
|
||||
else {
|
||||
$message = t('Finished with an error.');
|
||||
}
|
||||
drupal_set_message($message);
|
||||
}
|
||||
|
||||
}
|
||||
511
web/modules/custom/ufc/src/Fighter.php
Normal file
511
web/modules/custom/ufc/src/Fighter.php
Normal file
@@ -0,0 +1,511 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\ufc;
|
||||
|
||||
use Drupal\media\Entity\Media;
|
||||
use Drupal\node\Entity\Node;
|
||||
use Drupal\Component\Utility\Html;
|
||||
use GuzzleHttp\Client;
|
||||
use Drupal\taxonomy\Entity\Term;
|
||||
|
||||
class Fighter {
|
||||
|
||||
public $name;
|
||||
public $first_name;
|
||||
public $last_name;
|
||||
public $height;
|
||||
public $weight;
|
||||
public $age;
|
||||
public $reach;
|
||||
public $leg_reach;
|
||||
public $image;
|
||||
public $image_id;
|
||||
public $class;
|
||||
public $wins;
|
||||
public $losses;
|
||||
public $ties;
|
||||
public $http_client;
|
||||
public $fighter_page;
|
||||
public $striking_accuracy;
|
||||
public $grappling_accuracy;
|
||||
public $strikes_per_min;
|
||||
public $absorbed_per_min;
|
||||
public $takedowns_per_15;
|
||||
public $knockdown_ratio;
|
||||
public $knockouts;
|
||||
public $decisions;
|
||||
public $submissions;
|
||||
|
||||
/**
|
||||
* Public constructor.
|
||||
*
|
||||
* @param Client $httpClient
|
||||
*/
|
||||
public function __construct(Client $httpClient) {
|
||||
$this->http_client = $httpClient;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get fighters url from name.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getFighterUrl() {
|
||||
|
||||
// Manual overrides for name problems go here.
|
||||
if ($this->first_name == 'Khaos') {
|
||||
$this->first_name = 'Kalinn';
|
||||
}
|
||||
|
||||
if ($this->first_name == 'J') {
|
||||
$this->first_name = 'JP';
|
||||
$this->last_name = 'Buys';
|
||||
}
|
||||
|
||||
if ($this->last_name == 'Mc Kee') {
|
||||
$this->last_name = 'McKee';
|
||||
}
|
||||
|
||||
if ($this->last_name == 'Mc Gee') {
|
||||
$this->last_name = 'McGee';
|
||||
}
|
||||
|
||||
if ($this->last_name == 'Mc Gregor') {
|
||||
$this->last_name = 'mcgregor';
|
||||
}
|
||||
|
||||
if ($this->last_name == "O' Malley") {
|
||||
$this->last_name = 'Omalley';
|
||||
}
|
||||
|
||||
if ($this->first_name == "Don'") {
|
||||
$this->first_name = 'dontale';
|
||||
$this->last_name = 'mayes';
|
||||
}
|
||||
|
||||
if ($this->first_name == "Marc-") {
|
||||
$this->first_name = 'Marc';
|
||||
}
|
||||
|
||||
if ($this->first_name == "A") {
|
||||
$this->first_name = 'AJ';
|
||||
$this->last_name = 'Dobson';
|
||||
}
|
||||
|
||||
if ($this->first_name == "C") {
|
||||
$this->first_name = 'CB';
|
||||
$this->last_name = 'Dollaway';
|
||||
}
|
||||
|
||||
if ($this->last_name == "Della Maddalena") {
|
||||
$this->last_name = 'Della';
|
||||
}
|
||||
|
||||
if ($this->first_name == "Elizeudos") {
|
||||
$this->first_name = 'elizeu';
|
||||
$this->last_name = 'dos-santos';
|
||||
}
|
||||
|
||||
|
||||
if ($this->last_name == "La Flare") {
|
||||
$this->last_name = 'laflare';
|
||||
}
|
||||
|
||||
if ($this->first_name == "JoelÁlvarez") {
|
||||
$this->first_name = 'Joel';
|
||||
}
|
||||
|
||||
if ($this->last_name == "J Brown") {
|
||||
$this->first_name = 'TJ';
|
||||
$this->last_name = 'Brown';
|
||||
}
|
||||
|
||||
|
||||
if ($this->first_name == "Alexda") {
|
||||
$this->first_name = "alex-da";
|
||||
}
|
||||
|
||||
|
||||
if ($this->last_name == "Mc Kinney") {
|
||||
$this->last_name = "mckinney";
|
||||
}
|
||||
|
||||
if ($this->last_name == "Van Camp") {
|
||||
$this->last_name = "vancamp";
|
||||
}
|
||||
|
||||
if ($this->last_name == "J Laramie") {
|
||||
$this->first_name = "TJ";
|
||||
$this->last_name = "Laramie";
|
||||
}
|
||||
|
||||
if ($this->last_name == "Al- Qaisi") {
|
||||
$this->last_name = "alqaisi";
|
||||
}
|
||||
|
||||
if ($this->first_name == "Alatengheili") {
|
||||
$this->first_name = "heili";
|
||||
$this->last_name = "alateng";
|
||||
}
|
||||
|
||||
if ($this->last_name == "J Dillashaw") {
|
||||
$this->first_name = "TJ";
|
||||
$this->last_name = "Dillashaw";
|
||||
}
|
||||
|
||||
if ($this->first_name == "Andersondos") {
|
||||
$this->first_name = "Anderson-dos";
|
||||
}
|
||||
|
||||
if ($this->last_name == "Silvade Andrade") {
|
||||
$this->last_name = "Silva-de-andrade";
|
||||
}
|
||||
|
||||
if ($this->first_name == "Ode'") {
|
||||
$this->first_name = "ode";
|
||||
}
|
||||
|
||||
if ($this->first_name == "Sumudaerji") {
|
||||
$this->first_name = "su";
|
||||
$this->last_name = "mudaerji";
|
||||
}
|
||||
|
||||
$hyphens = str_replace(" ", "-", $this->last_name);
|
||||
$suffix = $this->first_name . "-" . $hyphens;
|
||||
|
||||
if ($this->first_name == "Aoriqileng") {
|
||||
$suffix = $this->first_name;
|
||||
}
|
||||
|
||||
$url = "https://www.ufc.com/athlete/$suffix";
|
||||
$trim = rtrim($url);
|
||||
return $url;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get contents of the fighter page.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function getFighterPage() {
|
||||
try {
|
||||
$request = $this->http_client->request('GET', $this->getFighterUrl(), ['verify' => FALSE]);
|
||||
$this->fighter_page = $request->getBody()->getContents();
|
||||
} catch (\Exception $e) {
|
||||
echo 'Caught exception: ', $e->getMessage(), "\n";
|
||||
// exit();
|
||||
}
|
||||
|
||||
/*
|
||||
USE THIS FOR TESTING:
|
||||
|
||||
$player_url = "https://www.ufc.com/athlete/anthony-hamilton";
|
||||
try {
|
||||
$request = $this->http_client->request('GET', $player_url);
|
||||
}
|
||||
catch (\Exception $e) {
|
||||
return FALSE;
|
||||
}
|
||||
$content = $request->getBody()->getContents();
|
||||
*/
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Get fighter age.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function getAge() {
|
||||
$pattern = '/<div class="field field--name-age(.*)<\/div>/';
|
||||
preg_match($pattern, $this->fighter_page, $matches);
|
||||
preg_match_all('!\d+!', $matches[0], $age);
|
||||
$fighter_age = reset($age[0]);
|
||||
$this->age = (float) $fighter_age;
|
||||
}
|
||||
|
||||
|
||||
public function getBio() {
|
||||
$pattern = '/<div class="c-bio__text">[0-9]+\.[0-9]+/s';
|
||||
preg_match_all($pattern, $this->fighter_page, $matches);
|
||||
$matches = reset($matches);
|
||||
|
||||
// Get height.
|
||||
$pattern = '/[0-9]+\.[0-9]+/';
|
||||
preg_match($pattern, $matches[0], $height);
|
||||
$this->height = reset($height);
|
||||
|
||||
// Get weight.
|
||||
$pattern = '/[0-9]+\.[0-9]+/';
|
||||
preg_match($pattern, $matches[1], $weight);
|
||||
$this->weight = reset($weight);
|
||||
|
||||
// Get reach.
|
||||
$pattern = '/[0-9]+\.[0-9]+/';
|
||||
preg_match($pattern, $matches[2], $reach);
|
||||
$this->reach = reset($reach);
|
||||
|
||||
// Get leg reach.
|
||||
$pattern = '/[0-9]+\.[0-9]+/';
|
||||
preg_match($pattern, $matches[3], $leg_reach);
|
||||
$this->leg_reach = reset($leg_reach);
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts the fighter record.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function getFighterRecord() {
|
||||
$pattern = "/[0-9]+[-][0-9]+[-][0-9]+.\(W-L-D\)/";
|
||||
preg_match($pattern, $this->fighter_page, $matches);
|
||||
$r = reset($matches);
|
||||
$r = str_replace(" (W-L-D)", "", $r);
|
||||
$record_chunks = explode("-", $r);
|
||||
$this->wins = $record_chunks[0];
|
||||
$this->losses = $record_chunks[1];
|
||||
$this->ties = $record_chunks[2];
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts the striking accuracy.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function getStrikingAccuracy() {
|
||||
$pattern = '/<title>Striking accuracy.(.*)<\/title>/';
|
||||
preg_match($pattern, $this->fighter_page, $matches);
|
||||
$this->striking_accuracy = str_replace('%', '', $matches[1]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts the grappling accuracy.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function getGrapplingAccuracy() {
|
||||
$pattern = '/<title>Grappling accuracy.(.*)<\/title>/';
|
||||
preg_match($pattern, $this->fighter_page, $matches);
|
||||
$this->grappling_accuracy = str_replace('%', '', $matches[1]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts averages from the statistics section.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function getAverages() {
|
||||
$pattern = '/<div class="c-stat-compare__group-1(.*)(<\/div>)/sU';
|
||||
preg_match_all($pattern, $this->fighter_page, $matches);
|
||||
$this->strikes_per_min = $this->extractNumber($matches[1][0]);
|
||||
$this->takedowns_per_15 = $this->extractNumber($matches[1][1]);
|
||||
$this->knockdown_ratio = $this->extractNumber($matches[1][3]);
|
||||
$pattern = '/<div class="c-stat-compare__group-2(.*)(<\/div>)/sU';
|
||||
preg_match_all($pattern, $this->fighter_page, $matches);
|
||||
$this->absorbed_per_min = $this->extractNumber($matches[1][0]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts wins per type.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function getWinsBreakdown() {
|
||||
$pattern = '/<div class="c-stat-3bar__value">(.*)<\/div>/sU';
|
||||
preg_match_all($pattern, $this->fighter_page, $matches);
|
||||
$this->knockouts = $this->extractWinByType($matches[0][3]);
|
||||
$this->decisions = $this->extractWinByType($matches[0][4]);
|
||||
$this->submissions = $this->extractWinByType($matches[0][5]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper to get number out of string.
|
||||
*
|
||||
* @param [type] $string
|
||||
* @return void
|
||||
*/
|
||||
protected function extractNumber($string) {
|
||||
$no_tags = strip_tags($string);
|
||||
preg_match_all('!\d+!', $no_tags, $matches);
|
||||
$number = implode('.', $matches[0]);
|
||||
return $number;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper to extract number from number and percentage.
|
||||
*
|
||||
* @param [type] $string
|
||||
* @return void
|
||||
*/
|
||||
protected function extractWinByType($string) {
|
||||
$no_tags = strip_tags($string);
|
||||
preg_match_all('!\d+!', $no_tags, $matches);
|
||||
return $matches[0][0];
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a player node.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function createPlayerNode() {
|
||||
$division_id = self::transformWeightClass();
|
||||
$title = $this->first_name . " " . $this->last_name;
|
||||
$node = Node::create([
|
||||
'type' => 'fighter',
|
||||
'title' => $title,
|
||||
'field_division' => self::getTermByName($division_id),
|
||||
'field_first_name' => $this->first_name,
|
||||
'field_last_name' => $this->last_name,
|
||||
'field_wins' => $this->wins,
|
||||
'field_losses' => $this->losses,
|
||||
'field_ties' => $this->ties,
|
||||
'field_player_photo' => [
|
||||
'target_id' => $this->image_id,
|
||||
],
|
||||
'field_striking_accuracy' => $this->striking_accuracy,
|
||||
'field_grappling_accuracy' => $this->grappling_accuracy,
|
||||
'field_strikes_per_minute' => $this->strikes_per_min,
|
||||
'field_absorbed_per_min' => $this->absorbed_per_min,
|
||||
'field_takedowns_per_15' => $this->takedowns_per_15,
|
||||
'field_knockdown_ratio' => $this->knockdown_ratio,
|
||||
'field_knockouts' => $this->knockouts,
|
||||
'field_decisions' => $this->decisions,
|
||||
'field_submissions' => $this->submissions,
|
||||
'field_age' => $this->age,
|
||||
'field_reach' => $this->reach,
|
||||
'field_leg_reach' => $this->leg_reach,
|
||||
'field_height' => $this->height,
|
||||
'field_weight' => $this->weight
|
||||
|
||||
]);
|
||||
$node->status = 1;
|
||||
$node->enforceIsNew();
|
||||
$node->save();
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates a player node.
|
||||
*
|
||||
* @param $nid
|
||||
* @return void
|
||||
*/
|
||||
public function updatePlayerNode($nid) {
|
||||
$node_storage = \Drupal::entityTypeManager()->getStorage('node');
|
||||
$node = $node_storage->load($nid);
|
||||
$node->field_wins = $this->wins;
|
||||
$node->field_losses = $this->losses;
|
||||
$node->field_ties = $this->ties;
|
||||
$node->field_striking_accuracy = $this->striking_accuracy;
|
||||
$node->field_grappling_accuracy = $this->grappling_accuracy;
|
||||
$node->field_strikes_per_minute = $this->strikes_per_min;
|
||||
$node->field_absorbed_per_min = $this->absorbed_per_min;
|
||||
$node->field_takedowns_per_15 = $this->takedowns_per_15;
|
||||
$node->field_knockdown_ratio = $this->knockdown_ratio;
|
||||
$node->field_knockouts = $this->knockouts;
|
||||
$node->field_decisions = $this->decisions;
|
||||
$node->field_submissions = $this->submissions;
|
||||
$node->field_age = $this->age;
|
||||
$node->field_reach = $this->reach;
|
||||
$node->field_leg_reach = $this->leg_reach;
|
||||
$node->field_height = $this->height;
|
||||
$node->field_weight = $this->weight;
|
||||
|
||||
$node->save();
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function to transform the weight class.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function transformWeightClass() {
|
||||
$weight_class = $this->class;
|
||||
$stripped = str_replace("_", " ", $weight_class);
|
||||
$upper = ucwords($stripped);
|
||||
return $upper;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function to retrieve taxo term by name.
|
||||
*
|
||||
* @param [type] $term_name
|
||||
* @return void
|
||||
*/
|
||||
public function getTermByName($term_name) {
|
||||
// Get taxonomy term storage.
|
||||
$taxonomyStorage = \Drupal::service('entity.manager')->getStorage('taxonomy_term');
|
||||
|
||||
// Set name properties.
|
||||
$properties['name'] = $term_name;
|
||||
$properties['vid'] = 'ufc_divisions';
|
||||
|
||||
// Load taxonomy term by properties.
|
||||
$terms = $taxonomyStorage->loadByProperties($properties);
|
||||
$term = reset($terms);
|
||||
|
||||
if (!$term) {
|
||||
$new_term = Term::create([
|
||||
'name' => $term_name,
|
||||
'vid' => 'ufc_divisions'
|
||||
])->save();
|
||||
|
||||
return $new_term;
|
||||
};
|
||||
|
||||
return $term->id();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create media for the player headshot.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function createMediaEntityFromImage() {
|
||||
$file_name = self::extractFileName();
|
||||
|
||||
if (empty($file_name)) {
|
||||
$rand = rand(0,100000000) . '.png';
|
||||
$file_name = "default-headshot_$rand";
|
||||
}
|
||||
|
||||
if (!empty($this->image)) {
|
||||
$file_data = file_get_contents($this->image);
|
||||
}
|
||||
|
||||
if (empty($file_data)) {
|
||||
$file_data = file_get_contents("public://player-headshots/headshot-default.png");
|
||||
}
|
||||
|
||||
$file = file_save_data(
|
||||
$file_data,
|
||||
"public://player-headshots/$file_name", FILE_EXISTS_RENAME);
|
||||
|
||||
$media_image = Media::create([
|
||||
'bundle' => 'image',
|
||||
'name' => $file_name,
|
||||
'field_media_image' => [
|
||||
'target_id' => $file->id(),
|
||||
],
|
||||
]);
|
||||
|
||||
$media_image->save();
|
||||
$this->image_id = $media_image->id();
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper to extract file name for images.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function extractFilename() {
|
||||
if (!empty($this->image)) {
|
||||
preg_match('/[A-Z_0-9]*.png/', $this->image, $matches);
|
||||
$file_name = reset($matches);
|
||||
return $file_name;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
}
|
||||
202
web/modules/custom/ufc/src/FighterImporter.php
Normal file
202
web/modules/custom/ufc/src/FighterImporter.php
Normal file
@@ -0,0 +1,202 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\ufc;
|
||||
|
||||
use Drupal\Core\Entity\EntityTypeManager;
|
||||
use Drupal\media\Media;
|
||||
use Drupal\ufc\Fighter;
|
||||
use GuzzleHttp\Client;
|
||||
|
||||
class FighterImporter {
|
||||
|
||||
protected $http_client;
|
||||
protected $entity_type_manager;
|
||||
protected $fighters = [];
|
||||
protected $weight_class;
|
||||
|
||||
// The base url for fighter lists.
|
||||
const UFC_BASE = "https://www.ufc.com/athletes/all?filters%5B0%5D=status%3A23&filters%5B1%5D=weight_class%3";
|
||||
|
||||
// These are the filter values used to cycle through divisions.
|
||||
protected $divisions = [
|
||||
'heavyweight' => "A11",
|
||||
'light_heavyweight' => "A13",
|
||||
'middleweight' => "A14",
|
||||
'welterweight' => "A15",
|
||||
'lightweight' => "A12",
|
||||
'featherweight' => "A9",
|
||||
'bantamweight' => "A8",
|
||||
'flyweight' => "A10",
|
||||
'strawweight' => "A99",
|
||||
];
|
||||
|
||||
/**
|
||||
* Public constructor for Fighter Importer.
|
||||
*
|
||||
* @param Client $httpClient
|
||||
* @param EntityTypeManager $entityTypeManager
|
||||
*/
|
||||
public function __construct(Client $httpClient, EntityTypeManager $entityTypeManager) {
|
||||
$this->http_client = $httpClient;
|
||||
$this->entity_type_manager = $entityTypeManager;
|
||||
}
|
||||
|
||||
public function importFighters() {
|
||||
// This will populate fighters array.
|
||||
$fighters_by_div = self::getListOfCurrentFighters();
|
||||
|
||||
// Process each fighter into system.
|
||||
foreach ($fighters_by_div as $division => $fighters) {
|
||||
foreach ($fighters as $fighter_data) {
|
||||
$fighter = new Fighter($this->http_client);
|
||||
$fighter->first_name = $fighter_data['firstname'];
|
||||
$fighter->last_name = $fighter_data['lastname'];
|
||||
$fighter->image = $fighter_data['image'];
|
||||
$fighter->class = $division;
|
||||
$fighter->getFighterPage();
|
||||
$fighter->getAge();
|
||||
$fighter->getBio();
|
||||
$fighter->getFighterRecord();
|
||||
$fighter->getStrikingAccuracy();
|
||||
$fighter->getGrapplingAccuracy();
|
||||
$fighter->getAverages();
|
||||
$fighter->getWinsBreakdown();
|
||||
$fighter->createMediaEntityFromImage();
|
||||
|
||||
// Check if node exists, by title.
|
||||
$title = $fighter->first_name . " " . $fighter->last_name;
|
||||
$node_lookup = reset($this->entity_type_manager->getStorage('node')->loadByProperties(['title' => $title]));
|
||||
|
||||
if (!empty($node_lookup)) {
|
||||
// Update instead of create.
|
||||
$fighter->updatePlayerNode($node_lookup->id());
|
||||
\Drupal::logger('ufc')->notice($fighter_data['firstname'] . " " . $fighter_data['lastname'] . " updated successfully.");
|
||||
}
|
||||
else {
|
||||
echo "didnt find an existing player, creating new for " . $title;
|
||||
$fighter->createPlayerNode();
|
||||
\Drupal::logger('ufc')->notice($fighter_data['firstname'] . " " . $fighter_data['lastname'] . " imported successfully.");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get list of current fighters.
|
||||
*
|
||||
* @return array $fighters
|
||||
*/
|
||||
public function getListOfCurrentFighters() {
|
||||
foreach ($this->divisions as $division => $div_base_url) {
|
||||
$division_url = self::UFC_BASE . $div_base_url;
|
||||
$this->weight_class = $division;
|
||||
echo "Starting import for " . $division . "\n";
|
||||
self::loopThroughFighterPages($division_url);
|
||||
}
|
||||
return $this->fighters;
|
||||
}
|
||||
|
||||
/**
|
||||
* There is a pager, loop through to get all fighters.
|
||||
*
|
||||
* @param string $base_url
|
||||
*/
|
||||
public function loopThroughFighterPages($base_url) {
|
||||
|
||||
for ($i=0; $i<=20; $i++) {
|
||||
$url = $base_url . "&page=$i";
|
||||
$request = $this->http_client->request('GET', $url, ['verify' => false]);
|
||||
$content = $request->getBody()->getContents();
|
||||
$check = strpos($content, "No Result Found For");
|
||||
|
||||
if (!$check) {
|
||||
echo "extracting fighters from page $i \n";
|
||||
self::extractFighters($content);
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract fighters from a page.
|
||||
*/
|
||||
public function extractFighters($input) {
|
||||
$pattern = '/<span class="c-listing-athlete__name">(.*)<\/span>/sU';
|
||||
preg_match_all($pattern, $input, $matches);
|
||||
|
||||
$fighter_names = [];
|
||||
|
||||
foreach ($matches[1] as $fighter_name) {
|
||||
$fighter_names[] = trim(html_entity_decode($fighter_name));
|
||||
}
|
||||
|
||||
$fighter_names = array_unique($fighter_names);
|
||||
|
||||
foreach ($fighter_names as $name) {
|
||||
$name_no_spaces = str_replace(" ", "", $name);
|
||||
$class_exists = array_key_exists($this->weight_class, $this->fighters);
|
||||
|
||||
$fighter_exists = null;
|
||||
|
||||
if ($class_exists) {
|
||||
$fighter_exists = array_key_exists($name_no_spaces, $this->fighters[$this->weight_class]);
|
||||
}
|
||||
|
||||
if (!$fighter_exists) {
|
||||
$chunks = preg_split('/(?=[A-Z])/', $name_no_spaces);
|
||||
$first_name = $chunks[1];
|
||||
$last_name_size = count($chunks);
|
||||
|
||||
switch($last_name_size) {
|
||||
case 3:
|
||||
$last_name = $chunks[2];
|
||||
break;
|
||||
case 4:
|
||||
$last_name = $chunks[2] . " " . $chunks[3];
|
||||
break;
|
||||
case 5:
|
||||
$last_name = $chunks[2] . " " . $chunks[3] . " " . $chunks[4];
|
||||
break;
|
||||
}
|
||||
|
||||
$this->fighters[$this->weight_class][$name_no_spaces]['firstname'] = $first_name;
|
||||
|
||||
$this->fighters[$this->weight_class][$name_no_spaces]['lastname'] = $last_name;
|
||||
}
|
||||
// Get image paths.
|
||||
$pattern = '/<div class="c-listing-athlete__thumbnail(.*)<\/div>/sU';
|
||||
preg_match_all($pattern, $input, $matches);
|
||||
|
||||
$images = [];
|
||||
|
||||
foreach ($matches[0] as $html_img) {
|
||||
$images[] = $this->extractImageSource($html_img);
|
||||
}
|
||||
|
||||
$name = strtoupper($last_name . '_' . $first_name);
|
||||
$fighter_image = $this->getFighterImageFromList($images, $name);
|
||||
$this->fighters[$this->weight_class][$name_no_spaces]['image'] = $fighter_image;
|
||||
}
|
||||
}
|
||||
|
||||
// Get the fighter image.
|
||||
public function extractImageSource($source_html) {
|
||||
$pattern = '/<img[^>]+src="([^">]+)"/';
|
||||
preg_match_all($pattern, $source_html, $image);
|
||||
return $image[1];
|
||||
}
|
||||
|
||||
// Extract a specific fighter image from a list.
|
||||
public function getFighterImageFromList($list, $fighter) {
|
||||
foreach ($list as $url_arr) {
|
||||
foreach ($url_arr as $url) {
|
||||
if (strpos($url, $fighter) !== FALSE) {
|
||||
return $url;
|
||||
}
|
||||
}
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
}
|
||||
54
web/modules/custom/ufc/src/Form/SelfHealKickoffForm.php
Normal file
54
web/modules/custom/ufc/src/Form/SelfHealKickoffForm.php
Normal file
@@ -0,0 +1,54 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\ufc\Form;
|
||||
|
||||
use Drupal\Core\Form\FormBase;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
|
||||
/**
|
||||
* Class SelfHealKickoffForm to start self heal in batches.
|
||||
*
|
||||
* @package Drupal\ufc\Form
|
||||
*/
|
||||
class SelfHealKickoffForm extends FormBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getFormId() {
|
||||
return 'self_heal_kickoff_form';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function buildForm(array $form, FormStateInterface $form_state) {
|
||||
$form['self_heal'] = array(
|
||||
'#type' => 'submit',
|
||||
'#value' => $this->t('Self Heal'),
|
||||
);
|
||||
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function submitForm(array &$form, FormStateInterface $form_state) {
|
||||
$fights = \Drupal::service('entity_type.manager')->getStorage('node')->loadByProperties(['type' => 'fight']);
|
||||
|
||||
$batch = array(
|
||||
'title' => t('Updating Fights...'),
|
||||
'operations' => array(
|
||||
array(
|
||||
'\Drupal\ufc\FightPredictor::updatePredictionsBatched',
|
||||
array($fights)
|
||||
),
|
||||
),
|
||||
'finished' => '\Drupal\ufc\FightPredictor::fightUpdatedCallback',
|
||||
);
|
||||
|
||||
batch_set($batch);
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user