DrdPlus/Theurgist/Spells/Formula.php
File `Formula.php` has 410 lines of code (exceeds 250 allowed). Consider refactoring.<?phpdeclare(strict_types=1); namespace DrdPlus\Theurgist\Spells; use DrdPlus\Codes\Units\DistanceUnitCode;use DrdPlus\Tables\Measurements\Distance\Distance;use DrdPlus\Tables\Measurements\Distance\DistanceBonus;use DrdPlus\Tables\Measurements\Distance\DistanceTable;use DrdPlus\Codes\Theurgist\FormulaCode;use DrdPlus\Codes\Theurgist\FormulaMutableSpellParameterCode;use DrdPlus\Codes\Theurgist\ModifierCode;use DrdPlus\Codes\Theurgist\ModifierMutableSpellParameterCode;use DrdPlus\Theurgist\Spells\SpellParameters\Attack;use DrdPlus\Theurgist\Spells\SpellParameters\Brightness;use DrdPlus\Theurgist\Spells\SpellParameters\CastingRounds;use DrdPlus\Theurgist\Spells\SpellParameters\DetailLevel;use DrdPlus\Theurgist\Spells\SpellParameters\Duration;use DrdPlus\Theurgist\Spells\SpellParameters\EpicenterShift;use DrdPlus\Theurgist\Spells\SpellParameters\Evocation;use DrdPlus\Theurgist\Spells\SpellParameters\FormulaDifficulty;use DrdPlus\Theurgist\Spells\SpellParameters\Partials\CastingParameter;use DrdPlus\Theurgist\Spells\SpellParameters\Power;use DrdPlus\Theurgist\Spells\SpellParameters\Radius;use DrdPlus\Theurgist\Spells\SpellParameters\Realm;use DrdPlus\Theurgist\Spells\SpellParameters\RealmsAffection;use DrdPlus\Theurgist\Spells\SpellParameters\SizeChange;use DrdPlus\Theurgist\Spells\SpellParameters\SpellSpeed;use Granam\Integer\Tools\ToInteger;use Granam\Strict\Object\StrictObject;use Granam\String\StringTools;use Granam\Tools\ValueDescriber; `Formula` has 32 functions (exceeds 20 allowed). Consider refactoring.
The class Formula has an overall complexity of 79 which is very high. The configured complexity threshold is 50.
The class Formula has a coupling between objects value of 38. Consider to reduce the number of dependencies under 13.class Formula extends StrictObject{ use ToFlatArrayTrait; /** @var FormulaCode */ private $formulaCode; /** @var FormulasTable */ private $formulasTable; /** @var DistanceTable */ private $distanceTable; /** @var int[] */Avoid excessively long variable names like $formulaSpellParameterChanges. Keep variable name length under 20. private $formulaSpellParameterChanges; /** @var Modifier[] */ private $modifiers; /** @var SpellTrait[] */ private $formulaSpellTraits; /** * @param FormulaCode $formulaCode * @param FormulasTable $formulasTable * @param DistanceTable $distanceTable * @param array $formulaSpellParameterValues Current values of spell parameters (changes will be calculated from them) * by @see FormulaMutableSpellParameterCode value indexed its value change * @param array|Modifier[] $modifiers * @param array|SpellTrait[] $formulaSpellTraits * @throws \DrdPlus\Theurgist\Spells\Exceptions\UselessValueForUnusedSpellParameter * @throws \DrdPlus\Theurgist\Spells\Exceptions\UnknownFormulaParameter * @throws \DrdPlus\Theurgist\Spells\Exceptions\InvalidValueForFormulaParameter * @throws \DrdPlus\Theurgist\Spells\Exceptions\InvalidModifier * @throws \DrdPlus\Theurgist\Spells\Exceptions\InvalidSpellTrait */ public function __construct(Method `__construct` has 6 arguments (exceeds 4 allowed). Consider refactoring. FormulaCode $formulaCode, FormulasTable $formulasTable, DistanceTable $distanceTable,Avoid excessively long variable names like $formulaSpellParameterValues. Keep variable name length under 20. array $formulaSpellParameterValues = [], array $modifiers = [], array $formulaSpellTraits = [] ) { $this->formulaCode = $formulaCode; $this->formulasTable = $formulasTable; $this->distanceTable = $distanceTable; // gets spell parameter changes as delta of current values and default values $this->formulaSpellParameterChanges = $this->sanitizeSpellParameterChanges($formulaSpellParameterValues); $this->modifiers = $this->getCheckedModifiers($this->toFlatArray($modifiers)); $this->formulaSpellTraits = $this->getCheckedSpellTraits($this->toFlatArray($formulaSpellTraits)); } /** * @param array $spellParameterValues * @return array * @throws \DrdPlus\Theurgist\Spells\Exceptions\UselessValueForUnusedSpellParameter * @throws \DrdPlus\Theurgist\Spells\Exceptions\InvalidValueForFormulaParameter * @throws \DrdPlus\Theurgist\Spells\Exceptions\UnknownFormulaParameter */Method `sanitizeSpellParameterChanges` has 34 lines of code (exceeds 25 allowed). Consider refactoring.
Function `sanitizeSpellParameterChanges` has a Cognitive Complexity of 9 (exceeds 5 allowed). Consider refactoring. private function sanitizeSpellParameterChanges(array $spellParameterValues): array { $sanitizedChanges = [];Avoid using static access to class '\DrdPlus\Codes\Theurgist\FormulaMutableSpellParameterCode' in method 'sanitizeSpellParameterChanges'.
Avoid excessively long variable names like $mutableSpellParameter. Keep variable name length under 20. foreach (FormulaMutableSpellParameterCode::getPossibleValues() as $mutableSpellParameter) { if (!\array_key_exists($mutableSpellParameter, $spellParameterValues)) { $sanitizedChanges[$mutableSpellParameter] = 0; continue; } try {Avoid using static access to class '\Granam\Integer\Tools\ToInteger' in method 'sanitizeSpellParameterChanges'. $sanitizedValue = ToInteger::toInteger($spellParameterValues[$mutableSpellParameter]); } catch (\Granam\Integer\Tools\Exceptions\Exception $exception) { throw new Exceptions\InvalidValueForFormulaParameter(Avoid using static access to class '\Granam\Tools\ValueDescriber' in method 'sanitizeSpellParameterChanges'. 'Expected integer, got ' . ValueDescriber::describe($spellParameterValues[$mutableSpellParameter]) . ' for ' . $mutableSpellParameter . ": '{$exception->getMessage()}'" ); } /** like @see FormulasTable::getCastingRounds() */Avoid using static access to class '\Granam\String\StringTools' in method 'sanitizeSpellParameterChanges'. $getParameter = StringTools::assembleGetterForName($mutableSpellParameter); /** @var CastingParameter $baseParameter */ $baseParameter = $this->formulasTable->$getParameter($this->getFormulaCode()); if ($baseParameter === null) { throw new Exceptions\UselessValueForUnusedSpellParameter( "Casting parameter {$mutableSpellParameter} is not used for formula {$this->formulaCode}"Avoid using static access to class '\Granam\Tools\ValueDescriber' in method 'sanitizeSpellParameterChanges'. . ', so given non-zero addition ' . ValueDescriber::describe($spellParameterValues[$mutableSpellParameter]) . ' is thrown away' ); } $parameterChange = $sanitizedValue - $baseParameter->getDefaultValue(); $sanitizedChanges[$mutableSpellParameter] = $parameterChange; unset($spellParameterValues[$mutableSpellParameter]); } if (\count($spellParameterValues) > 0) { // there are some remains throw new Exceptions\UnknownFormulaParameter( 'Unexpected mutable spells parameter(s) [' . \implode(', ', array_keys($spellParameterValues)) . ']. Expected only 'Avoid using static access to class '\DrdPlus\Codes\Theurgist\FormulaMutableSpellParameterCode' in method 'sanitizeSpellParameterChanges'. . \implode(', ', FormulaMutableSpellParameterCode::getPossibleValues()) ); } return $sanitizedChanges; } /** * @param array $modifiers * @return array|Modifier[] * @throws \DrdPlus\Theurgist\Spells\Exceptions\InvalidModifier */ private function getCheckedModifiers(array $modifiers): array { foreach ($modifiers as $modifier) { if (!is_a($modifier, Modifier::class)) { throw new Exceptions\InvalidModifier(Avoid using static access to class '\Granam\Tools\ValueDescriber' in method 'getCheckedModifiers'. 'Expected instance of ' . Modifier::class . ', got ' . ValueDescriber::describe($modifier) ); } } return $modifiers; } /** * @param array $spellTraits * @return array|SpellTrait[] * @throws \DrdPlus\Theurgist\Spells\Exceptions\InvalidSpellTrait */ private function getCheckedSpellTraits(array $spellTraits): array { foreach ($spellTraits as $spellTrait) { if (!is_a($spellTrait, SpellTrait::class)) { throw new Exceptions\InvalidSpellTrait(Avoid using static access to class '\Granam\Tools\ValueDescriber' in method 'getCheckedSpellTraits'. 'Expected instance of ' . Modifier::class . ', got ' . ValueDescriber::describe($spellTrait) ); } } return $spellTraits; } /** * All modifiers in a flat array (with removed tree structure) * * @return array|Modifier[] */ public function getModifiers(): array { return $this->modifiers; } /** * @return FormulaDifficulty * @throws \Granam\Integer\Tools\Exceptions\Exception */Method `getCurrentDifficulty` has 35 lines of code (exceeds 25 allowed). Consider refactoring. public function getCurrentDifficulty(): FormulaDifficulty { $formulaParameters = [ $this->getAttackWithAddition(), $this->getBrightnessWithAddition(), $this->getDetailLevelWithAddition(), $this->getDurationWithAddition(), $this->getEpicenterShiftWithAddition(), $this->getPowerWithAddition(), $this->getRadiusWithAddition(), $this->getSizeChangeWithAddition(), $this->getSpellSpeedWithAddition(), ]; $formulaParameters = array_filter( $formulaParameters, function (CastingParameter $formulaParameter = null) { return $formulaParameter !== null; } );Avoid excessively long variable names like $parametersDifficultyChangeSum. Keep variable name length under 20. $parametersDifficultyChangeSum = 0; /** @var CastingParameter $formulaParameter */ foreach ($formulaParameters as $formulaParameter) { $parametersDifficultyChangeSum += $formulaParameter->getAdditionByDifficulty()->getCurrentDifficultyIncrement(); }Avoid excessively long variable names like $modifiersDifficultyChangeSum. Keep variable name length under 20. $modifiersDifficultyChangeSum = 0; foreach ($this->modifiers as $modifier) { $modifiersDifficultyChangeSum += $modifier->getDifficultyChange()->getValue(); }Avoid excessively long variable names like $spellTraitsDifficultyChangeSum. Keep variable name length under 20. $spellTraitsDifficultyChangeSum = 0; foreach ($this->formulaSpellTraits as $spellTrait) { $spellTraitsDifficultyChangeSum += $spellTrait->getDifficultyChange()->getValue(); } $formulaDifficulty = $this->formulasTable->getFormulaDifficulty($this->getFormulaCode()); return $formulaDifficulty->createWithChange( $parametersDifficultyChangeSum + $modifiersDifficultyChangeSum + $spellTraitsDifficultyChangeSum ); } /** * @return CastingRounds */ public function getCurrentCastingRounds(): CastingRounds { $castingRoundsSum = 0; foreach ($this->modifiers as $modifier) { $castingRoundsSum += $modifier->getCastingRounds()->getValue(); } $castingRoundsSum += $this->formulasTable->getCastingRounds($this->getFormulaCode())->getValue(); return new CastingRounds([$castingRoundsSum]); } /** * Evocation time is not affected by any modifier or trait. * * @return Evocation */ public function getCurrentEvocation(): Evocation { return $this->formulasTable->getEvocation($this->getFormulaCode()); } /** * Daily, monthly and lifetime affections of realms * * @return array|RealmsAffection[] */ public function getCurrentRealmsAffections(): array { $realmsAffections = []; foreach ($this->getRealmsAffectionsSum() as $periodName => $periodSum) { $realmsAffections[$periodName] = new RealmsAffection([$periodSum, $periodName]); } return $realmsAffections; } /** * @return array|int[] by affection period indexed summary of that period realms-affection */Function `getRealmsAffectionsSum` has a Cognitive Complexity of 6 (exceeds 5 allowed). Consider refactoring. private function getRealmsAffectionsSum(): array { $baseRealmsAffection = $this->formulasTable->getRealmsAffection($this->getFormulaCode()); $realmsAffectionsSum = [ // like daily => -2 $baseRealmsAffection->getAffectionPeriod()->getValue() => $baseRealmsAffection->getValue(), ]; foreach ($this->modifiers as $modifier) {Avoid excessively long variable names like $modifierRealmsAffection. Keep variable name length under 20. $modifierRealmsAffection = $modifier->getRealmsAffection(); if ($modifierRealmsAffection === null) { continue; }Avoid excessively long variable names like $modifierRealmsAffectionPeriod. Keep variable name length under 20. $modifierRealmsAffectionPeriod = $modifierRealmsAffection->getAffectionPeriod()->getValue(); if (!array_key_exists($modifierRealmsAffectionPeriod, $realmsAffectionsSum)) { $realmsAffectionsSum[$modifierRealmsAffectionPeriod] = 0; } $realmsAffectionsSum[$modifierRealmsAffectionPeriod] += $modifierRealmsAffection->getValue(); } return $realmsAffectionsSum; } /** * Gives the highest required realm (by difficulty, by formula itself or by one of its modifiers) * * @return Realm * @throws \Granam\Integer\Tools\Exceptions\Exception */ public function getRequiredRealm(): Realm { $realmsIncrement = $this->getCurrentDifficulty()->getCurrentRealmsIncrement(); $realm = $this->formulasTable->getRealm($this->getFormulaCode()); $requiredRealm = $realm->add($realmsIncrement); foreach ($this->modifiers as $modifier) {Avoid excessively long variable names like $byModifierRequiredRealm. Keep variable name length under 20. $byModifierRequiredRealm = $modifier->getRequiredRealm(); if ($requiredRealm->getValue() < $byModifierRequiredRealm->getValue()) { // some modifier requires even higher realm, so we are forced to increase it $requiredRealm = $byModifierRequiredRealm; } } return $requiredRealm; } /** * @return FormulaCode */ public function getFormulaCode(): FormulaCode { return $this->formulaCode; } /** * Final radius including direct formula change and all its active traits and modifiers. * * @return Radius|null * @throws \Granam\Integer\Tools\Exceptions\Exception */ public function getCurrentRadius(): ?Radius { $radiusWithAddition = $this->getRadiusWithAddition(); if (!$radiusWithAddition) { return null; } Avoid excessively long variable names like $radiusModifiersChange. Keep variable name length under 20. $radiusModifiersChange = $this->getParameterBonusFromModifiers(ModifierMutableSpellParameterCode::RADIUS); if (!$radiusModifiersChange) { return new Radius([$radiusWithAddition->getValue(), 0]); } return new Radius([$radiusWithAddition->getValue() + $radiusModifiersChange, 0]); } /** * Formula radius extended by direct formula change * * @return Radius|null * @throws \Granam\Integer\Tools\Exceptions\Exception */ private function getRadiusWithAddition(): ?Radius { $baseRadius = $this->formulasTable->getRadius($this->formulaCode); if ($baseRadius === null) { return null; } return $baseRadius->getWithAddition($this->formulaSpellParameterChanges[FormulaMutableSpellParameterCode::RADIUS]); } /** * Any formula (spell) can be shifted * * @return EpicenterShift|null * @throws \Granam\Integer\Tools\Exceptions\Exception */ public function getCurrentEpicenterShift(): ?EpicenterShift {Avoid excessively long variable names like $epicenterShiftWithAddition. Keep variable name length under 20. $epicenterShiftWithAddition = $this->getEpicenterShiftWithAddition();Avoid excessively long variable names like $epicenterShiftByModifiers. Keep variable name length under 20. $epicenterShiftByModifiers = $this->getParameterBonusFromModifiers(ModifierMutableSpellParameterCode::EPICENTER_SHIFT); if ($epicenterShiftWithAddition === null) { if ($epicenterShiftByModifiers === false) { return null; } return new EpicenterShift( [$epicenterShiftByModifiers['bonus'], 0 /* no added difficulty*/], new Distance($epicenterShiftByModifiers['meters'], DistanceUnitCode::METER, $this->distanceTable) ); } if ($epicenterShiftByModifiers === false) { return $epicenterShiftWithAddition; } $meters = $epicenterShiftWithAddition->getDistance($this->distanceTable)->getMeters(); $meters += $epicenterShiftByModifiers['meters']; $distance = new Distance($meters, DistanceUnitCode::METER, $this->distanceTable); return new EpicenterShift([$distance->getBonus(), 0 /* no added difficulty */], $distance); } /** * @return EpicenterShift|null * @throws \Granam\Integer\Tools\Exceptions\Exception */ private function getEpicenterShiftWithAddition(): ?EpicenterShift { $baseEpicenterShift = $this->formulasTable->getEpicenterShift($this->formulaCode); if ($baseEpicenterShift === null) { return null; } return $baseEpicenterShift->getWithAddition($this->formulaSpellParameterChanges[FormulaMutableSpellParameterCode::EPICENTER_SHIFT]); } /** * Any formula (spell) can get a power, even if was passive and not harming before * * @return Power|null * @throws \Granam\Integer\Tools\Exceptions\Exception */Similar blocks of code found in 2 locations. Consider refactoring. public function getCurrentPower(): ?Power { $powerWithAddition = $this->getPowerWithAddition(); $powerBonus = $this->getParameterBonusFromModifiers(ModifierMutableSpellParameterCode::POWER); if (!$powerWithAddition && $powerBonus === false) { return null; } return new Power([ ($powerWithAddition ? $powerWithAddition->getValue() : 0) + (int)$powerBonus, 0, // no addition ]); } /** * @return Power|null * @throws \Granam\Integer\Tools\Exceptions\Exception */ private function getPowerWithAddition(): ?Power { $basePower = $this->formulasTable->getPower($this->formulaCode); if ($basePower === null) { return null; } return $basePower->getWithAddition($this->formulaSpellParameterChanges[FormulaMutableSpellParameterCode::POWER]); } /** * Attack can be only increased, not added. * * @return Attack|null * @throws \Granam\Integer\Tools\Exceptions\Exception */ public function getCurrentAttack(): ?Attack { $attackWithAddition = $this->getAttackWithAddition(); if (!$attackWithAddition) { return null; } return new Attack([ $attackWithAddition->getValue() + (int)$this->getParameterBonusFromModifiers(ModifierMutableSpellParameterCode::ATTACK), 0 // no addition ]); } /** * @return Attack|null * @throws \Granam\Integer\Tools\Exceptions\Exception */ private function getAttackWithAddition(): ?Attack { $baseAttack = $this->formulasTable->getAttack($this->formulaCode); if ($baseAttack === null) { return null; } return $baseAttack->getWithAddition($this->formulaSpellParameterChanges[FormulaMutableSpellParameterCode::ATTACK]); } /** * @param string $parameterName * @return bool|int|array|int[] */Function `getParameterBonusFromModifiers` has a Cognitive Complexity of 15 (exceeds 5 allowed). Consider refactoring.
Method `getParameterBonusFromModifiers` has 31 lines of code (exceeds 25 allowed). Consider refactoring. private function getParameterBonusFromModifiers(string $parameterName) { $bonusParts = []; foreach ($this->modifiers as $modifier) { if ($modifier->getModifierCode()->getValue() === ModifierCode::GATE) { continue; // gate does not give bonus to a parameter, it is standalone being with its own parameters } if ($parameterName === ModifierMutableSpellParameterCode::POWER && $modifier->getModifierCode()->getValue() === ModifierCode::THUNDER ) { continue; // thunder power means a noise, does not affects formula power }Avoid using static access to class '\Granam\String\StringTools' in method 'getParameterBonusFromModifiers'.
Avoid excessively long variable names like $getParameterWithAddition. Keep variable name length under 20. $getParameterWithAddition = StringTools::assembleGetterForName($parameterName . 'WithAddition'); /** like @see Modifier::getAttackWithAddition() */ $parameter = $modifier->$getParameterWithAddition(); if ($parameter === null) { continue; } /** @var CastingParameter $parameter */ $bonusParts[] = $parameter->getValue(); } if (\count($bonusParts) === 0) { return false; } // transpositions are chained in sequence and their values (distances) have to be summed, not bonuses if ($parameterName === ModifierMutableSpellParameterCode::EPICENTER_SHIFT) { $meters = 0; foreach ($bonusParts as $bonusPart) { $meters += (new DistanceBonus($bonusPart, $this->distanceTable))->getDistance()->getMeters(); } return [ 'bonus' => (new Distance($meters, DistanceUnitCode::METER, $this->distanceTable))->getBonus()->getValue(), 'meters' => $meters, ]; } return (int)\array_sum($bonusParts); } /** * Any formula (spell) can get a speed, even if was static before * * @return SpellSpeed|null * @throws \Granam\Integer\Tools\Exceptions\Exception */Similar blocks of code found in 2 locations. Consider refactoring. public function getCurrentSpellSpeed(): ?SpellSpeed {Avoid excessively long variable names like $spellSpeedWithAddition. Keep variable name length under 20. $spellSpeedWithAddition = $this->getSpellSpeedWithAddition(); $spellSpeedBonus = $this->getParameterBonusFromModifiers(ModifierMutableSpellParameterCode::SPELL_SPEED); if (!$spellSpeedWithAddition && $spellSpeedBonus === false) { return null; } return new SpellSpeed([ ($spellSpeedWithAddition ? $spellSpeedWithAddition->getValue() : 0) + (int)$spellSpeedBonus, 0, ]); } /** * @return SpellSpeed|null * @throws \Granam\Integer\Tools\Exceptions\Exception */ private function getSpellSpeedWithAddition(): ?SpellSpeed { $baseSpellSpeed = $this->formulasTable->getSpellSpeed($this->formulaCode); if ($baseSpellSpeed === null) { return null; } return $baseSpellSpeed->getWithAddition($this->formulaSpellParameterChanges[FormulaMutableSpellParameterCode::SPELL_SPEED]); } /** * @return DetailLevel|null * @throws \Granam\Integer\Tools\Exceptions\Exception */ public function getCurrentDetailLevel(): ?DetailLevel { return $this->getDetailLevelWithAddition(); } /** * @return DetailLevel|null * @throws \Granam\Integer\Tools\Exceptions\Exception */ private function getDetailLevelWithAddition(): ?DetailLevel { $baseDetailLevel = $this->formulasTable->getDetailLevel($this->formulaCode); if ($baseDetailLevel === null) { return null; } return $baseDetailLevel->getWithAddition($this->formulaSpellParameterChanges[FormulaMutableSpellParameterCode::DETAIL_LEVEL]); } /** * @return Brightness|null * @throws \Granam\Integer\Tools\Exceptions\Exception */ public function getCurrentBrightness(): ?Brightness { return $this->getBrightnessWithAddition(); } /** * @return Brightness|null * @throws \Granam\Integer\Tools\Exceptions\Exception */ private function getBrightnessWithAddition(): ?Brightness { $baseBrightness = $this->formulasTable->getBrightness($this->formulaCode); if ($baseBrightness === null) { return null; } return $baseBrightness->getWithAddition($this->formulaSpellParameterChanges[FormulaMutableSpellParameterCode::BRIGHTNESS]); } /** * @return Duration * @throws \Granam\Integer\Tools\Exceptions\Exception */ public function getCurrentDuration(): Duration { return $this->getDurationWithAddition(); } /** * @return Duration * @throws \Granam\Integer\Tools\Exceptions\Exception */ private function getDurationWithAddition(): Duration { $baseDuration = $this->formulasTable->getDuration($this->formulaCode); return $baseDuration->getWithAddition($this->formulaSpellParameterChanges[FormulaMutableSpellParameterCode::DURATION]); } /** * @return SizeChange|null * @throws \Granam\Integer\Tools\Exceptions\Exception */ public function getCurrentSizeChange(): ?SizeChange { return $this->getSizeChangeWithAddition(); } /** * @return SizeChange|null * @throws \Granam\Integer\Tools\Exceptions\Exception */ private function getSizeChangeWithAddition(): ?SizeChange { $baseSizeChange = $this->formulasTable->getSizeChange($this->formulaCode); if ($baseSizeChange === null) { return null; } return $baseSizeChange->getWithAddition($this->formulaSpellParameterChanges[FormulaMutableSpellParameterCode::SIZE_CHANGE]); } public function __toString() { return $this->getFormulaCode()->getValue(); } }