Passed
Branch feature/2.0 (d2af8f)
by Jonathan
13:07
created

SosaStatistics::handle()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 27
Code Lines 19

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 3
eloc 19
c 1
b 0
f 0
nc 3
nop 1
dl 0
loc 27
rs 9.6333
1
<?php
2
3
/**
4
 * webtrees-lib: MyArtJaub library for webtrees
5
 *
6
 * @package MyArtJaub\Webtrees
7
 * @subpackage Sosa
8
 * @author Jonathan Jaubart <[email protected]>
9
 * @copyright Copyright (c) 2009-2020, Jonathan Jaubart
10
 * @license http://www.gnu.org/licenses/gpl.html GNU General Public License, version 3
11
 */
12
13
declare(strict_types=1);
14
15
namespace MyArtJaub\Webtrees\Module\Sosa\Http\RequestHandlers;
16
17
use Fisharebest\Webtrees\Auth;
18
use Fisharebest\Webtrees\DefaultUser;
19
use Fisharebest\Webtrees\I18N;
20
use Fisharebest\Webtrees\Tree;
21
use Fisharebest\Webtrees\Exceptions\HttpNotFoundException;
22
use Fisharebest\Webtrees\Http\ViewResponseTrait;
23
use Fisharebest\Webtrees\Module\ModuleThemeInterface;
24
use Fisharebest\Webtrees\Services\ModuleService;
25
use MyArtJaub\Webtrees\Module\Sosa\SosaModule;
26
use MyArtJaub\Webtrees\Module\Sosa\Services\SosaStatisticsService;
27
use Psr\Http\Message\ResponseInterface;
28
use Psr\Http\Message\ServerRequestInterface;
29
use Psr\Http\Server\RequestHandlerInterface;
30
31
/**
32
 * Request handler for listing Sosa ancestors
33
 *
34
 */
35
class SosaStatistics implements RequestHandlerInterface
36
{
37
    use ViewResponseTrait;
38
    
39
    /**
40
     * @var SosaModule $module
41
     */
42
    private $module;
43
    
44
    /**
45
     * Constructor for AncestorsList Request Handler
46
     *
47
     * @param ModuleService $module_service
48
     */
49
    public function __construct(
50
        ModuleService $module_service
51
    ) {
52
        $this->module = $module_service->findByInterface(SosaModule::class)->first();
53
    }
54
    
55
    /**
56
     * {@inheritDoc}
57
     * @see \Psr\Http\Server\RequestHandlerInterface::handle()
58
     */
59
    public function handle(ServerRequestInterface $request): ResponseInterface
60
    {
61
        if ($this->module === null) {
62
            throw new HttpNotFoundException(I18N::translate('The attached module could not be found.'));
63
        }
64
        
65
        $tree = $request->getAttribute('tree');
66
        assert($tree instanceof Tree);
67
        
68
        $user = Auth::check() ? $request->getAttribute('user') : new DefaultUser();
69
        
70
        /** @var SosaStatisticsService $sosa_stats_service */
71
        $sosa_stats_service = app()->makeWith(SosaStatisticsService::class, ['tree' => $tree, 'user' => $user]);
72
        
73
        return $this->viewResponse($this->module->name() . '::statistics-page', [
74
            'module_name'       =>  $this->module->name(),
75
            'title'             =>  I18N::translate('Sosa Statistics'),
76
            'tree'              =>  $tree,
77
            'theme'             =>  app(ModuleThemeInterface::class),
78
            'root_indi'         =>  $sosa_stats_service->rootIndividual(),
79
            'general_stats'     =>  $this->statisticsGeneral($sosa_stats_service),
80
            'generation_stats'  =>  $this->statisticsByGenerations($sosa_stats_service),
81
            'generation_depth'  =>  $sosa_stats_service->generationDepthStatsAtGeneration(1)->first(),
82
            'multiple_sosas'    =>  $sosa_stats_service->topMultipleAncestorsWithNoTies(10)->groupBy('sosa_count'),
83
            'sosa_dispersion_g2'=>  $sosa_stats_service->ancestorsDispersionForGeneration(2),
84
            'sosa_dispersion_g3'=>  $sosa_stats_service->ancestorsDispersionForGeneration(3),
85
            'gen_depth_g3'      =>  $sosa_stats_service->generationDepthStatsAtGeneration(3)
86
        ]);
87
    }
88
    
89
    /**
90
     * Retrieve and compute the global statistics of ancestors for the tree.
91
     * Statistics include the number of ancestors, the number of different ancestors, pedigree collapse...
92
     * 
93
     * @param SosaStatisticsService sosa_stats_service
0 ignored issues
show
Bug introduced by
The type MyArtJaub\Webtrees\Modul...lers\sosa_stats_service was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
94
     * @return array<string, int|float>
95
     */
96
    private function statisticsGeneral(SosaStatisticsService $sosa_stats_service) : array
97
    {
98
        $ancestors_count = $sosa_stats_service->totalAncestors();
99
        $ancestors_distinct_count = $sosa_stats_service->totalDistinctAncestors();
100
        $individual_count = $sosa_stats_service->totalIndividuals();
101
        
102
        return [
103
            'sosa_count'            =>  $ancestors_count,
104
            'distinct_count'        =>  $ancestors_distinct_count,
105
            'sosa_rate'             =>  $this->safeDivision($ancestors_distinct_count, $individual_count),
106
            'pedi_collapse'         =>  1 - $this->safeDivision($ancestors_distinct_count, $ancestors_count),
107
            'mean_gen_time'         =>  $sosa_stats_service->meanGenerationTime()
108
        ];
109
    }
110
    
111
    /**
112
     * Retrieve and compute the statistics of ancestors by generations.
113
     * Statistics include the number of ancestors, the number of different ancestors, cumulative statistics...
114
     * 
115
     * @param SosaStatisticsService $sosa_stats_service
116
     * @return array<int, array<string, int|float>
0 ignored issues
show
Documentation Bug introduced by
The doc comment array<int, array<string, int|float> at position 11 could not be parsed: Expected '>' at position 11, but found '>'.
Loading history...
117
     */
118
    private function statisticsByGenerations(SosaStatisticsService $sosa_stats_service) : array
119
    {
120
        $stats_by_gen = $sosa_stats_service->statisticsByGenerations();
121
        
122
        $generation_stats = array();
123
        
124
        foreach($stats_by_gen as $gen => $stats_gen){
125
            $gen_diff = $gen > 1 ?$stats_gen['diffSosaTotalCount'] - $stats_by_gen[$gen - 1]['diffSosaTotalCount'] : 1;
126
            $generation_stats[$gen] = array(
127
                'gen_min_birth' => $stats_gen['firstBirth'] ?? $stats_gen['firstEstimatedBirth'],
128
                'gen_max_birth' => $stats_gen['lastBirth'] ?? $stats_gen['lastEstimatedBirth'],
129
                'theoretical' => pow(2, $gen - 1),
130
                'known' => $stats_gen['sosaCount'],
131
                'perc_known' => $this->safeDivision($stats_gen['sosaCount'], pow(2, $gen - 1)),
132
                'missing' => $gen > 1 ? 2 * $stats_by_gen[$gen - 1]['sosaCount'] - $stats_gen['sosaCount'] : 0,
133
                'perc_missing' => $gen > 1 ? 1 - $this->safeDivision($stats_gen['sosaCount'],  2 * $stats_by_gen[$gen - 1]['sosaCount']) : 0,
134
                'total_known' => $stats_gen['sosaTotalCount'],
135
                'perc_total_known' => $this->safeDivision($stats_gen['sosaTotalCount'], pow(2, $gen) - 1),
136
                'different' => $gen_diff,
137
                'perc_different' => $this->safeDivision($gen_diff, $stats_gen['sosaCount']),
138
                'total_different' => $stats_gen['diffSosaTotalCount'],
139
                'pedi_collapse' => 1 - $this->safeDivision($stats_gen['diffSosaTotalCount'], $stats_gen['sosaTotalCount'])
140
            );
141
        }
142
        
143
        return $generation_stats;
144
    }
145
    
146
    /**
147
     * Return the result of a division, and a default value if denominator is 0
148
     * 
149
     * @param int $p Numerator
150
     * @param int $q Denominator
151
     * @param float $default Value if denominator is 0
152
     * @return float
153
     */
154
    private function safeDivision(int $p, int $q, float $default = 0) : float
155
    {
156
        return $q == 0 ? $default : $p / $q;
157
    }
158
}
159