1<?php 2 3/** 4 * webtrees: online genealogy 5 * Copyright (C) 2019 webtrees development team 6 * This program is free software: you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License as published by 8 * the Free Software Foundation, either version 3 of the License, or 9 * (at your option) any later version. 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * You should have received a copy of the GNU General Public License 15 * along with this program. If not, see <http://www.gnu.org/licenses/>. 16 */ 17 18declare(strict_types=1); 19 20namespace Fisharebest\Webtrees\Module; 21 22use Fisharebest\Webtrees\Carbon; 23use Fisharebest\Webtrees\Gedcom; 24use Fisharebest\Webtrees\GedcomTag; 25use Fisharebest\Webtrees\I18N; 26use Fisharebest\Webtrees\Services\CalendarService; 27use Fisharebest\Webtrees\Tree; 28use Illuminate\Support\Str; 29use Psr\Http\Message\ServerRequestInterface; 30 31/** 32 * Class OnThisDayModule 33 */ 34class OnThisDayModule extends AbstractModule implements ModuleBlockInterface 35{ 36 use ModuleBlockTrait; 37 38 // Pagination 39 private const LIMIT_LOW = 10; 40 private const LIMIT_HIGH = 20; 41 42 // Initial sorting for datatables 43 private const DATATABLES_ORDER = [ 44 'alpha' => [[0, 'asc']], 45 'anniv' => [[2, 'asc']], 46 ]; 47 48 // All standard GEDCOM 5.5.1 events except CENS, RESI and EVEN 49 private const ALL_EVENTS = [ 50 'ADOP', 51 'ANUL', 52 'BAPM', 53 'BARM', 54 'BASM', 55 'BIRT', 56 'BLES', 57 'BURI', 58 'CHR', 59 'CHRA', 60 'CONF', 61 'CREM', 62 'DEAT', 63 'DIV', 64 'DIVF', 65 'EMIG', 66 'ENGA', 67 'FCOM', 68 'GRAD', 69 'IMMI', 70 'MARB', 71 'MARC', 72 'MARL', 73 'MARR', 74 'MARS', 75 'NATU', 76 'ORDN', 77 'PROB', 78 'RETI', 79 'WILL', 80 ]; 81 82 private const DEFAULT_EVENTS = [ 83 'BIRT', 84 'MARR', 85 'DEAT', 86 ]; 87 88 /** 89 * How should this module be identified in the control panel, etc.? 90 * 91 * @return string 92 */ 93 public function title(): string 94 { 95 /* I18N: Name of a module */ 96 return I18N::translate('On this day'); 97 } 98 99 /** 100 * A sentence describing what this module does. 101 * 102 * @return string 103 */ 104 public function description(): string 105 { 106 /* I18N: Description of the “On this day” module */ 107 return I18N::translate('A list of the anniversaries that occur today.'); 108 } 109 110 /** 111 * Generate the HTML content of this block. 112 * 113 * @param Tree $tree 114 * @param int $block_id 115 * @param string $context 116 * @param string[] $config 117 * 118 * @return string 119 */ 120 public function getBlock(Tree $tree, int $block_id, string $context, array $config = []): string 121 { 122 $calendar_service = new CalendarService(); 123 124 $default_events = implode(',', self::DEFAULT_EVENTS); 125 126 $filter = (bool) $this->getBlockSetting($block_id, 'filter', '1'); 127 $infoStyle = $this->getBlockSetting($block_id, 'infoStyle', 'table'); 128 $sortStyle = $this->getBlockSetting($block_id, 'sortStyle', 'alpha'); 129 $events = $this->getBlockSetting($block_id, 'events', $default_events); 130 131 extract($config, EXTR_OVERWRITE); 132 133 $event_array = explode(',', $events); 134 135 // If we are only showing living individuals, then we don't need to search for DEAT events. 136 if ($filter) { 137 $event_array = array_diff($event_array, Gedcom::DEATH_EVENTS); 138 } 139 140 $events_filter = implode('|', $event_array); 141 142 $startjd = Carbon::now()->julianDay(); 143 $endjd = $startjd; 144 145 $facts = $calendar_service->getEventsList($startjd, $endjd, $events_filter, $filter, $sortStyle, $tree); 146 147 if ($facts->isEmpty()) { 148 $content = view('modules/todays_events/empty'); 149 } elseif ($infoStyle === 'list') { 150 $content = view('lists/anniversaries-list', [ 151 'id' => $block_id, 152 'facts' => $facts, 153 'limit_low' => self::LIMIT_LOW, 154 'limit_high' => self::LIMIT_HIGH, 155 ]); 156 } else { 157 $content = view('lists/anniversaries-table', [ 158 'facts' => $facts, 159 'limit_low' => self::LIMIT_LOW, 160 'limit_high' => self::LIMIT_HIGH, 161 'order' => self::DATATABLES_ORDER[$sortStyle], 162 ]); 163 } 164 165 if ($context !== self::CONTEXT_EMBED) { 166 return view('modules/block-template', [ 167 'block' => Str::kebab($this->name()), 168 'id' => $block_id, 169 'config_url' => $this->configUrl($tree, $context, $block_id), 170 'title' => $this->title(), 171 'content' => $content, 172 ]); 173 } 174 175 return $content; 176 } 177 178 /** 179 * Should this block load asynchronously using AJAX? 180 * 181 * Simple blocks are faster in-line, more complex ones can be loaded later. 182 * 183 * @return bool 184 */ 185 public function loadAjax(): bool 186 { 187 return true; 188 } 189 190 /** 191 * Can this block be shown on the user’s home page? 192 * 193 * @return bool 194 */ 195 public function isUserBlock(): bool 196 { 197 return true; 198 } 199 200 /** 201 * Can this block be shown on the tree’s home page? 202 * 203 * @return bool 204 */ 205 public function isTreeBlock(): bool 206 { 207 return true; 208 } 209 210 /** 211 * Update the configuration for a block. 212 * 213 * @param ServerRequestInterface $request 214 * @param int $block_id 215 * 216 * @return void 217 */ 218 public function saveBlockConfiguration(ServerRequestInterface $request, int $block_id): void 219 { 220 $params = (array) $request->getParsedBody(); 221 222 $this->setBlockSetting($block_id, 'filter', $params['filter']); 223 $this->setBlockSetting($block_id, 'infoStyle', $params['infoStyle']); 224 $this->setBlockSetting($block_id, 'sortStyle', $params['sortStyle']); 225 $this->setBlockSetting($block_id, 'events', implode(',', $params['events'] ?? [])); 226 } 227 228 /** 229 * An HTML form to edit block settings 230 * 231 * @param Tree $tree 232 * @param int $block_id 233 * 234 * @return string 235 */ 236 public function editBlockConfiguration(Tree $tree, int $block_id): string 237 { 238 $default_events = implode(',', self::DEFAULT_EVENTS); 239 240 $filter = $this->getBlockSetting($block_id, 'filter', '1'); 241 $infoStyle = $this->getBlockSetting($block_id, 'infoStyle', 'table'); 242 $sortStyle = $this->getBlockSetting($block_id, 'sortStyle', 'alpha'); 243 $events = $this->getBlockSetting($block_id, 'events', $default_events); 244 245 $event_array = explode(',', $events); 246 247 $all_events = []; 248 foreach (self::ALL_EVENTS as $event) { 249 $all_events[$event] = GedcomTag::getLabel($event); 250 } 251 252 $info_styles = [ 253 /* I18N: An option in a list-box */ 254 'list' => I18N::translate('list'), 255 /* I18N: An option in a list-box */ 256 'table' => I18N::translate('table'), 257 ]; 258 259 $sort_styles = [ 260 /* I18N: An option in a list-box */ 261 'alpha' => I18N::translate('sort by name'), 262 /* I18N: An option in a list-box */ 263 'anniv' => I18N::translate('sort by date'), 264 ]; 265 266 return view('modules/todays_events/config', [ 267 'all_events' => $all_events, 268 'event_array' => $event_array, 269 'filter' => $filter, 270 'infoStyle' => $infoStyle, 271 'info_styles' => $info_styles, 272 'sortStyle' => $sortStyle, 273 'sort_styles' => $sort_styles, 274 ]); 275 } 276} 277