summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--app/Family.php8
-rw-r--r--app/Functions/FunctionsExport.php10
-rw-r--r--app/GedcomRecord.php20
-rw-r--r--app/Http/Controllers/Admin/FixLevel0MediaController.php15
-rw-r--r--app/Http/Controllers/Admin/ImportThumbnailsController.php48
-rw-r--r--app/Http/Controllers/Admin/MediaController.php17
-rw-r--r--app/Http/Controllers/AutocompleteController.php4
-rw-r--r--app/Http/Controllers/BranchesController.php2
-rw-r--r--app/Http/Controllers/ListController.php8
-rw-r--r--app/Http/Controllers/PlaceHierarchyController.php4
-rw-r--r--app/Http/RequestHandlers/ExportGedcomClient.php2
-rw-r--r--app/Http/RequestHandlers/UpdatePlacesAction.php4
-rw-r--r--app/Individual.php13
-rw-r--r--app/Media.php8
-rw-r--r--app/Module/ResearchTaskModule.php4
-rw-r--r--app/Module/SiteMapModule.php12
-rw-r--r--app/Note.php8
-rw-r--r--app/Repository.php8
-rw-r--r--app/Services/SearchService.php160
-rw-r--r--app/Source.php8
-rw-r--r--app/Statistics/Repository/FamilyRepository.php10
-rw-r--r--app/Statistics/Repository/IndividualRepository.php6
-rw-r--r--app/Tree.php15
-rw-r--r--tests/app/Http/Controllers/Admin/FixLevel0MediaControllerTest.php12
-rw-r--r--tests/app/Http/Controllers/Admin/ImportThumbnailsControllerTest.php11
-rw-r--r--tests/app/Http/Controllers/Admin/MediaControllerTest.php19
-rw-r--r--tests/app/Services/SearchServiceTest.php3
27 files changed, 295 insertions, 144 deletions
diff --git a/app/Family.php b/app/Family.php
index 0c4027bac8..f80330085e 100644
--- a/app/Family.php
+++ b/app/Family.php
@@ -70,12 +70,14 @@ class Family extends GedcomRecord
/**
* A closure which will create a record from a database row.
*
+ * @param Tree $tree
+ *
* @return Closure
*/
- public static function rowMapper(): Closure
+ public static function rowMapper(Tree $tree): Closure
{
- return static function (stdClass $row): Family {
- return Family::getInstance($row->f_id, Tree::findById((int) $row->f_file), $row->f_gedcom);
+ return static function (stdClass $row) use ($tree): Family {
+ return Family::getInstance($row->f_id, $tree, $row->f_gedcom);
};
}
diff --git a/app/Functions/FunctionsExport.php b/app/Functions/FunctionsExport.php
index d6c899fcc1..a28c857af5 100644
--- a/app/Functions/FunctionsExport.php
+++ b/app/Functions/FunctionsExport.php
@@ -181,7 +181,7 @@ class FunctionsExport
->where('m_file', '=', $tree->id())
->orderBy('m_id')
->get()
- ->map(Media::rowMapper())
+ ->map(Media::rowMapper($tree))
->map(static function (Media $record) use ($access_level): string {
return $record->privatizeGedcom($access_level);
})
@@ -193,7 +193,7 @@ class FunctionsExport
->where('s_file', '=', $tree->id())
->orderBy('s_id')
->get()
- ->map(Source::rowMapper())
+ ->map(Source::rowMapper($tree))
->map(static function (Source $record) use ($access_level): string {
return $record->privatizeGedcom($access_level);
});
@@ -203,7 +203,7 @@ class FunctionsExport
->whereNotIn('o_type', ['HEAD', 'TRLR'])
->orderBy('o_id')
->get()
- ->map(GedcomRecord::rowMapper())
+ ->map(GedcomRecord::rowMapper($tree))
->map(static function (GedcomRecord $record) use ($access_level): string {
return $record->privatizeGedcom($access_level);
});
@@ -212,7 +212,7 @@ class FunctionsExport
->where('i_file', '=', $tree->id())
->orderBy('i_id')
->get()
- ->map(Individual::rowMapper())
+ ->map(Individual::rowMapper($tree))
->map(static function (Individual $record) use ($access_level): string {
return $record->privatizeGedcom($access_level);
});
@@ -221,7 +221,7 @@ class FunctionsExport
->where('f_file', '=', $tree->id())
->orderBy('f_id')
->get()
- ->map(Family::rowMapper())
+ ->map(Family::rowMapper($tree))
->map(static function (Family $record) use ($access_level): string {
return $record->privatizeGedcom($access_level);
});
diff --git a/app/GedcomRecord.php b/app/GedcomRecord.php
index 3e93b64633..0353b17079 100644
--- a/app/GedcomRecord.php
+++ b/app/GedcomRecord.php
@@ -85,12 +85,14 @@ class GedcomRecord
/**
* A closure which will create a record from a database row.
*
+ * @param Tree $tree
+ *
* @return Closure
*/
- public static function rowMapper(): Closure
+ public static function rowMapper(Tree $tree): Closure
{
- return static function (stdClass $row): GedcomRecord {
- return GedcomRecord::getInstance($row->o_id, Tree::findById((int) $row->o_file), $row->o_gedcom);
+ return static function (stdClass $row) use ($tree): GedcomRecord {
+ return GedcomRecord::getInstance($row->o_id, $tree, $row->o_gedcom);
};
}
@@ -696,7 +698,7 @@ class GedcomRecord
->where('l_to', '=', $this->xref)
->select(['individuals.*'])
->get()
- ->map(Individual::rowMapper())
+ ->map(Individual::rowMapper($this->tree))
->filter(self::accessFilter());
}
@@ -720,7 +722,7 @@ class GedcomRecord
->where('l_to', '=', $this->xref)
->select(['families.*'])
->get()
- ->map(Family::rowMapper())
+ ->map(Family::rowMapper($this->tree))
->filter(self::accessFilter());
}
@@ -744,7 +746,7 @@ class GedcomRecord
->where('l_to', '=', $this->xref)
->select(['sources.*'])
->get()
- ->map(Source::rowMapper())
+ ->map(Source::rowMapper($this->tree))
->filter(self::accessFilter());
}
@@ -768,7 +770,7 @@ class GedcomRecord
->where('l_to', '=', $this->xref)
->select(['media.*'])
->get()
- ->map(Media::rowMapper())
+ ->map(Media::rowMapper($this->tree))
->filter(self::accessFilter());
}
@@ -793,7 +795,7 @@ class GedcomRecord
->where('l_to', '=', $this->xref)
->select(['other.*'])
->get()
- ->map(Note::rowMapper())
+ ->map(Note::rowMapper($this->tree))
->filter(self::accessFilter());
}
@@ -818,7 +820,7 @@ class GedcomRecord
->where('l_to', '=', $this->xref)
->select(['other.*'])
->get()
- ->map(Repository::rowMapper())
+ ->map(Repository::rowMapper($this->tree))
->filter(self::accessFilter());
}
diff --git a/app/Http/Controllers/Admin/FixLevel0MediaController.php b/app/Http/Controllers/Admin/FixLevel0MediaController.php
index ef8290fc3a..924107a404 100644
--- a/app/Http/Controllers/Admin/FixLevel0MediaController.php
+++ b/app/Http/Controllers/Admin/FixLevel0MediaController.php
@@ -24,7 +24,7 @@ use Fisharebest\Webtrees\I18N;
use Fisharebest\Webtrees\Individual;
use Fisharebest\Webtrees\Media;
use Fisharebest\Webtrees\Services\DatatablesService;
-use Fisharebest\Webtrees\Tree;
+use Fisharebest\Webtrees\Services\TreeService;
use Illuminate\Database\Capsule\Manager as DB;
use Illuminate\Database\Query\Expression;
use Illuminate\Database\Query\JoinClause;
@@ -41,14 +41,19 @@ class FixLevel0MediaController extends AbstractAdminController
/** @var DatatablesService */
private $datatables_service;
+ /** @var TreeService */
+ private $tree_service;
+
/**
* FixLevel0MediaController constructor.
*
* @param DatatablesService $datatables_service
+ * @param TreeService $tree_service
*/
- public function __construct(DatatablesService $datatables_service)
+ public function __construct(DatatablesService $datatables_service, TreeService $tree_service)
{
$this->datatables_service = $datatables_service;
+ $this->tree_service = $tree_service;
}
/**
@@ -80,7 +85,7 @@ class FixLevel0MediaController extends AbstractAdminController
$obje_xref = $request->getParsedBody()['obje_xref'];
$tree_id = (int) $request->getParsedBody()['tree_id'];
- $tree = Tree::findById($tree_id);
+ $tree = $this->tree_service->find($tree_id);
$individual = Individual::getInstance($indi_xref, $tree);
$media = Media::getInstance($obje_xref, $tree);
@@ -147,8 +152,8 @@ class FixLevel0MediaController extends AbstractAdminController
->orderBy('media.m_id')
->select(['media.m_file', 'media.m_id', 'media.m_gedcom', 'individuals.i_id', 'individuals.i_gedcom']);
- return $this->datatables_service->handleQuery($request, $query, [], [], static function (stdClass $datum) use ($ignore_facts): array {
- $tree = Tree::findById((int) $datum->m_file);
+ return $this->datatables_service->handleQuery($request, $query, [], [], function (stdClass $datum) use ($ignore_facts): array {
+ $tree = $this->tree_service->find((int) $datum->m_file);
$media = Media::getInstance($datum->m_id, $tree, $datum->m_gedcom);
$individual = Individual::getInstance($datum->i_id, $tree, $datum->i_gedcom);
diff --git a/app/Http/Controllers/Admin/ImportThumbnailsController.php b/app/Http/Controllers/Admin/ImportThumbnailsController.php
index f74c1543b1..8141786097 100644
--- a/app/Http/Controllers/Admin/ImportThumbnailsController.php
+++ b/app/Http/Controllers/Admin/ImportThumbnailsController.php
@@ -22,11 +22,9 @@ namespace Fisharebest\Webtrees\Http\Controllers\Admin;
use Fisharebest\Webtrees\I18N;
use Fisharebest\Webtrees\Media;
use Fisharebest\Webtrees\Services\PendingChangesService;
+use Fisharebest\Webtrees\Services\SearchService;
use Fisharebest\Webtrees\Services\TreeService;
use Fisharebest\Webtrees\Webtrees;
-use Illuminate\Database\Capsule\Manager as DB;
-use Illuminate\Database\Query\Expression;
-use Illuminate\Database\Query\JoinClause;
use Illuminate\Support\Collection;
use Intervention\Image\ImageManager;
use League\Flysystem\Filesystem;
@@ -41,21 +39,29 @@ use function assert;
*/
class ImportThumbnailsController extends AbstractAdminController
{
- /** @var TreeService */
- private $tree_service;
-
/** @var PendingChangesService */
private $pending_changes_service;
+ /** @var SearchService */
+ private $search_service;
+
+ /** @var TreeService */
+ private $tree_service;
+
/**
* ImportThumbnailsController constructor.
*
* @param PendingChangesService $pending_changes_service
+ * @param SearchService $search_service
* @param TreeService $tree_service
*/
- public function __construct(PendingChangesService $pending_changes_service, TreeService $tree_service)
- {
+ public function __construct(
+ PendingChangesService $pending_changes_service,
+ SearchService $search_service,
+ TreeService $tree_service
+ ) {
$this->pending_changes_service = $pending_changes_service;
+ $this->search_service = $search_service;
$this->tree_service = $tree_service;
}
@@ -191,7 +197,7 @@ class ImportThumbnailsController extends AbstractAdminController
$original_path = substr($original, strlen(WT_DATA_DIR));
$thumbnail_path = substr($thumbnail, strlen(WT_DATA_DIR));
- $media = $this->findMediaObjectsForMediaFile($original_path);
+ $media = $this->search_service->findMediaObjectsForMediaFile($original_path);
$media_links = array_map(static function (Media $media): string {
return '<a href="' . e($media->url()) . '">' . $media->fullName() . '</a>';
@@ -247,30 +253,6 @@ class ImportThumbnailsController extends AbstractAdminController
}
/**
- * Find the media object that uses a particular media file.
- *
- * @param string $file
- *
- * @return Media[]
- */
- private function findMediaObjectsForMediaFile(string $file): array
- {
- return DB::table('media')
- ->join('media_file', static function (JoinClause $join): void {
- $join
- ->on('media_file.m_file', '=', 'media.m_file')
- ->on('media_file.m_id', '=', 'media.m_id');
- })
- ->join('gedcom_setting', 'media.m_file', '=', 'gedcom_setting.gedcom_id')
- ->where(new Expression('setting_value || multimedia_file_refn'), '=', $file)
- ->select(['media.*'])
- ->distinct()
- ->get()
- ->map(Media::rowMapper())
- ->all();
- }
-
- /**
* Compare two images, and return a quantified difference.
* 0 (different) ... 100 (same)
*
diff --git a/app/Http/Controllers/Admin/MediaController.php b/app/Http/Controllers/Admin/MediaController.php
index 7e2242c4b3..90b712b1dd 100644
--- a/app/Http/Controllers/Admin/MediaController.php
+++ b/app/Http/Controllers/Admin/MediaController.php
@@ -29,6 +29,7 @@ use Fisharebest\Webtrees\Media;
use Fisharebest\Webtrees\MediaFile;
use Fisharebest\Webtrees\Services\DatatablesService;
use Fisharebest\Webtrees\Services\MediaFileService;
+use Fisharebest\Webtrees\Services\TreeService;
use Illuminate\Database\Capsule\Manager as DB;
use Illuminate\Database\Query\Builder;
use Illuminate\Database\Query\Expression;
@@ -74,16 +75,24 @@ class MediaController extends AbstractAdminController
/** @var MediaFileService */
private $media_file_service;
+ /** @var TreeService */
+ private $tree_service;
+
/**
* MediaController constructor.
*
* @param DatatablesService $datatables_service
* @param MediaFileService $media_file_service
+ * @param TreeService $tree_service
*/
- public function __construct(DatatablesService $datatables_service, MediaFileService $media_file_service)
- {
+ public function __construct(
+ DatatablesService $datatables_service,
+ MediaFileService $media_file_service,
+ TreeService $tree_service
+ ) {
$this->datatables_service = $datatables_service;
$this->media_file_service = $media_file_service;
+ $this->tree_service = $tree_service;
}
/**
@@ -158,7 +167,9 @@ class MediaController extends AbstractAdminController
// Convert a row from the database into a row for datatables
$callback = function (stdClass $row): array {
/** @var Media $media */
- $media = Media::rowMapper()($row);
+ $tree = $this->tree_service->find((int) $row->m_file);
+ $media = Media::getInstance($row->m_id, $tree, $row->m_gedcom);
+ assert($media instanceof Media);
$media_files = $media->mediaFiles()
->filter(static function (MediaFile $media_file) use ($row): bool {
diff --git a/app/Http/Controllers/AutocompleteController.php b/app/Http/Controllers/AutocompleteController.php
index 8708476b29..62c6b2e2d0 100644
--- a/app/Http/Controllers/AutocompleteController.php
+++ b/app/Http/Controllers/AutocompleteController.php
@@ -137,7 +137,7 @@ class AutocompleteController extends AbstractBaseController
->distinct()
->select(['individuals.*'])
->get()
- ->map(Individual::rowMapper())
+ ->map(Individual::rowMapper($tree))
->filter(GedcomRecord::accessFilter());
$families = DB::table('families')
@@ -153,7 +153,7 @@ class AutocompleteController extends AbstractBaseController
->distinct()
->select(['families.*'])
->get()
- ->map(Family::rowMapper())
+ ->map(Family::rowMapper($tree))
->filter(GedcomRecord::accessFilter());
$pages = new Collection();
diff --git a/app/Http/Controllers/BranchesController.php b/app/Http/Controllers/BranchesController.php
index 0692e90d91..58fdd40ba1 100644
--- a/app/Http/Controllers/BranchesController.php
+++ b/app/Http/Controllers/BranchesController.php
@@ -214,7 +214,7 @@ class BranchesController extends AbstractBaseController
->select(['individuals.*'])
->distinct()
->get()
- ->map(Individual::rowMapper())
+ ->map(Individual::rowMapper($tree))
->filter(GedcomRecord::accessFilter())
->all();
diff --git a/app/Http/Controllers/ListController.php b/app/Http/Controllers/ListController.php
index 3b42c60fd0..1ce9cc1667 100644
--- a/app/Http/Controllers/ListController.php
+++ b/app/Http/Controllers/ListController.php
@@ -616,7 +616,7 @@ class ListController extends AbstractBaseController
return $query
->get()
- ->map(Media::rowMapper())
+ ->map(Media::rowMapper($tree))
->filter(GedcomRecord::accessFilter())
->all();
}
@@ -634,7 +634,7 @@ class ListController extends AbstractBaseController
->where('o_file', '=', $tree->id())
->where('o_type', '=', 'NOTE')
->get()
- ->map(Note::rowMapper())
+ ->map(Note::rowMapper($tree))
->filter(GedcomRecord::accessFilter());
}
@@ -651,7 +651,7 @@ class ListController extends AbstractBaseController
->where('o_file', '=', $tree->id())
->where('o_type', '=', 'REPO')
->get()
- ->map(Repository::rowMapper())
+ ->map(Repository::rowMapper($tree))
->filter(GedcomRecord::accessFilter());
}
@@ -667,7 +667,7 @@ class ListController extends AbstractBaseController
return DB::table('sources')
->where('s_file', '=', $tree->id())
->get()
- ->map(Source::rowMapper())
+ ->map(Source::rowMapper($tree))
->filter(GedcomRecord::accessFilter());
}
diff --git a/app/Http/Controllers/PlaceHierarchyController.php b/app/Http/Controllers/PlaceHierarchyController.php
index d370bca6b4..3d9c6db68e 100644
--- a/app/Http/Controllers/PlaceHierarchyController.php
+++ b/app/Http/Controllers/PlaceHierarchyController.php
@@ -213,7 +213,7 @@ class PlaceHierarchyController extends AbstractBaseController
->select(['individuals.*'])
->distinct()
->get()
- ->map(Individual::rowMapper())
+ ->map(Individual::rowMapper($tree))
->filter(Individual::accessFilter())
->all();
@@ -228,7 +228,7 @@ class PlaceHierarchyController extends AbstractBaseController
->select(['families.*'])
->distinct()
->get()
- ->map(Family::rowMapper())
+ ->map(Family::rowMapper($tree))
->filter(Family::accessFilter())
->all();
diff --git a/app/Http/RequestHandlers/ExportGedcomClient.php b/app/Http/RequestHandlers/ExportGedcomClient.php
index cc1b70510a..615e028001 100644
--- a/app/Http/RequestHandlers/ExportGedcomClient.php
+++ b/app/Http/RequestHandlers/ExportGedcomClient.php
@@ -118,7 +118,7 @@ class ExportGedcomClient implements RequestHandlerInterface
$records = DB::table('media')
->where('m_file', '=', $tree->id())
->get()
- ->map(Media::rowMapper())
+ ->map(Media::rowMapper($tree))
->filter(GedcomRecord::accessFilter());
foreach ($records as $record) {
diff --git a/app/Http/RequestHandlers/UpdatePlacesAction.php b/app/Http/RequestHandlers/UpdatePlacesAction.php
index 1a1499029a..281e3f8574 100644
--- a/app/Http/RequestHandlers/UpdatePlacesAction.php
+++ b/app/Http/RequestHandlers/UpdatePlacesAction.php
@@ -63,14 +63,14 @@ class UpdatePlacesAction implements RequestHandlerInterface
->whereContains('i_gedcom', $search)
->select(['individuals.*'])
->get()
- ->map(Individual::rowMapper());
+ ->map(Individual::rowMapper($tree));
$family_changes = DB::table('families')
->where('f_file', '=', $tree->id())
->whereContains('f_gedcom', $search)
->select(['families.*'])
->get()
- ->map(Family::rowMapper());
+ ->map(Family::rowMapper($tree));
$changes = $individual_changes->merge($family_changes)
->mapWithKeys(static function (GedcomRecord $record) use ($search, $replace): array {
diff --git a/app/Individual.php b/app/Individual.php
index 78cebb2247..0400bbdfa8 100644
--- a/app/Individual.php
+++ b/app/Individual.php
@@ -49,14 +49,19 @@ class Individual extends GedcomRecord
/**
* A closure which will create a record from a database row.
*
+ * @param Tree $tree
+ *
* @return Closure
*/
- public static function rowMapper(): Closure
+ public static function rowMapper(Tree $tree): Closure
{
- return static function (stdClass $row): Individual {
- $individual = Individual::getInstance($row->i_id, Tree::findById((int) $row->i_file), $row->i_gedcom);
+ return static function (stdClass $row) use ($tree): Individual {
+ $individual = Individual::getInstance($row->i_id, $tree, $row->i_gedcom);
+ assert($individual instanceof Individual);
- if ($row->n_num ?? null) {
+ // Some queries include the names table.
+ // For these we must select the specified name.
+ if (($row->n_num ?? null) !== null) {
$individual = clone $individual;
$individual->setPrimaryName($row->n_num);
diff --git a/app/Media.php b/app/Media.php
index 00a08cee29..dd9ff06624 100644
--- a/app/Media.php
+++ b/app/Media.php
@@ -39,12 +39,14 @@ class Media extends GedcomRecord
/**
* A closure which will create a record from a database row.
*
+ * @param Tree $tree
+ *
* @return Closure
*/
- public static function rowMapper(): Closure
+ public static function rowMapper(Tree $tree): Closure
{
- return static function (stdClass $row): Media {
- return Media::getInstance($row->m_id, Tree::findById((int) $row->m_file), $row->m_gedcom);
+ return static function (stdClass $row) use ($tree): Media {
+ return Media::getInstance($row->m_id, $tree, $row->m_gedcom);
};
}
diff --git a/app/Module/ResearchTaskModule.php b/app/Module/ResearchTaskModule.php
index 32cab10a3e..b8b99a2ff1 100644
--- a/app/Module/ResearchTaskModule.php
+++ b/app/Module/ResearchTaskModule.php
@@ -218,7 +218,7 @@ class ResearchTaskModule extends AbstractModule implements ModuleBlockInterface
->select(['families.*'])
->distinct()
->get()
- ->map(Family::rowMapper())
+ ->map(Family::rowMapper($tree))
->filter(GedcomRecord::accessFilter());
}
@@ -242,7 +242,7 @@ class ResearchTaskModule extends AbstractModule implements ModuleBlockInterface
->select(['individuals.*'])
->distinct()
->get()
- ->map(Individual::rowMapper())
+ ->map(Individual::rowMapper($tree))
->filter(GedcomRecord::accessFilter());
}
}
diff --git a/app/Module/SiteMapModule.php b/app/Module/SiteMapModule.php
index bc8778b509..23be12c852 100644
--- a/app/Module/SiteMapModule.php
+++ b/app/Module/SiteMapModule.php
@@ -221,7 +221,7 @@ class SiteMapModule extends AbstractModule implements ModuleConfigInterface
if ($timestamp > $expiry_time) {
$content = $this->getPreference('sitemap-' . $file . '.xml');
} else {
- $tree = Tree::findById((int) $match[1]);
+ $tree = $this->tree_service->find((int) $match[1]);
if ($tree === null) {
throw new NotFoundHttpException('No such tree');
@@ -295,7 +295,7 @@ class SiteMapModule extends AbstractModule implements ModuleConfigInterface
->skip($offset)
->take($limit)
->get()
- ->map(Individual::rowMapper());
+ ->map(Individual::rowMapper($tree));
}
/**
@@ -313,7 +313,7 @@ class SiteMapModule extends AbstractModule implements ModuleConfigInterface
->skip($offset)
->take($limit)
->get()
- ->map(Media::rowMapper());
+ ->map(Media::rowMapper($tree));
}
/**
@@ -332,7 +332,7 @@ class SiteMapModule extends AbstractModule implements ModuleConfigInterface
->skip($offset)
->take($limit)
->get()
- ->map(Note::rowMapper());
+ ->map(Note::rowMapper($tree));
}
/**
@@ -351,7 +351,7 @@ class SiteMapModule extends AbstractModule implements ModuleConfigInterface
->skip($offset)
->take($limit)
->get()
- ->map(Repository::rowMapper());
+ ->map(Repository::rowMapper($tree));
}
/**
@@ -369,6 +369,6 @@ class SiteMapModule extends AbstractModule implements ModuleConfigInterface
->skip($offset)
->take($limit)
->get()
- ->map(Source::rowMapper());
+ ->map(Source::rowMapper($tree));
}
}
diff --git a/app/Note.php b/app/Note.php
index cd01e130f2..81bdeab96c 100644
--- a/app/Note.php
+++ b/app/Note.php
@@ -38,12 +38,14 @@ class Note extends GedcomRecord
/**
* A closure which will create a record from a database row.
*
+ * @param Tree $tree
+ *
* @return Closure
*/
- public static function rowMapper(): Closure
+ public static function rowMapper(Tree $tree): Closure
{
- return static function (stdClass $row): Note {
- return Note::getInstance($row->o_id, Tree::findById((int) $row->o_file), $row->o_gedcom);
+ return static function (stdClass $row) use ($tree): Note {
+ return Note::getInstance($row->o_id, $tree, $row->o_gedcom);
};
}
diff --git a/app/Repository.php b/app/Repository.php
index c5eb61c5da..157f24f074 100644
--- a/app/Repository.php
+++ b/app/Repository.php
@@ -37,12 +37,14 @@ class Repository extends GedcomRecord
/**
* A closure which will create a record from a database row.
*
+ * @param Tree $tree
+ *
* @return Closure
*/
- public static function rowMapper(): Closure
+ public static function rowMapper(Tree $tree): Closure
{
- return static function (stdClass $row): Repository {
- return Repository::getInstance($row->o_id, Tree::findById((int) $row->o_file), $row->o_gedcom);
+ return static function (stdClass $row) use ($tree): Repository {
+ return Repository::getInstance($row->o_id, $tree, $row->o_gedcom);
};
}
diff --git a/app/Services/SearchService.php b/app/Services/SearchService.php
index d71350389a..0441865f43 100644
--- a/app/Services/SearchService.php
+++ b/app/Services/SearchService.php
@@ -48,6 +48,19 @@ use function mb_stripos;
*/
class SearchService
{
+ /** @var TreeService */
+ private $tree_service;
+
+ /**
+ * SearchService constructor.
+ *
+ * @param TreeService $tree_service
+ */
+ public function __construct(TreeService $tree_service)
+ {
+ $this->tree_service = $tree_service;
+ }
+
/**
* @param Tree[] $trees
* @param string[] $search
@@ -64,7 +77,7 @@ class SearchService
return $query
->get()
->each($this->rowLimiter())
- ->map(Family::rowMapper())
+ ->map($this->familyRowMapper())
->filter(GedcomRecord::accessFilter())
->filter($this->rawGedcomFilter($search));
}
@@ -107,7 +120,7 @@ class SearchService
->select(['families.*', 'husb_name.n_sort', 'wife_name.n_sort'])
->distinct();
- return $this->paginateQuery($query, Family::rowMapper(), GedcomRecord::accessFilter(), $offset, $limit);
+ return $this->paginateQuery($query, $this->familyRowMapper(), GedcomRecord::accessFilter(), $offset, $limit);
}
/**
@@ -126,7 +139,7 @@ class SearchService
return $query
->get()
->each($this->rowLimiter())
- ->map(Individual::rowMapper())
+ ->map($this->individualRowMapper())
->filter(GedcomRecord::accessFilter())
->filter($this->rawGedcomFilter($search));
}
@@ -155,7 +168,7 @@ class SearchService
$this->whereTrees($query, 'i_file', $trees);
$this->whereSearch($query, 'n_full', $search);
- return $this->paginateQuery($query, Individual::rowMapper(), GedcomRecord::accessFilter(), $offset, $limit);
+ return $this->paginateQuery($query, $this->individualRowMapper(), GedcomRecord::accessFilter(), $offset, $limit);
}
/**
@@ -175,7 +188,7 @@ class SearchService
$this->whereTrees($query, 'media.m_file', $trees);
$this->whereSearch($query, 'm_gedcom', $search);
- return $this->paginateQuery($query, Media::rowMapper(), GedcomRecord::accessFilter(), $offset, $limit);
+ return $this->paginateQuery($query, $this->mediaRowMapper(), GedcomRecord::accessFilter(), $offset, $limit);
}
/**
@@ -196,7 +209,7 @@ class SearchService
$this->whereTrees($query, 'o_file', $trees);
$this->whereSearch($query, 'o_gedcom', $search);
- return $this->paginateQuery($query, Note::rowMapper(), GedcomRecord::accessFilter(), $offset, $limit);
+ return $this->paginateQuery($query, $this->noteRowMapper(), GedcomRecord::accessFilter(), $offset, $limit);
}
/**
@@ -217,7 +230,7 @@ class SearchService
$this->whereTrees($query, 'o_file', $trees);
$this->whereSearch($query, 'o_gedcom', $search);
- return $this->paginateQuery($query, Repository::rowMapper(), GedcomRecord::accessFilter(), $offset, $limit);
+ return $this->paginateQuery($query, $this->repositoryRowMapper(), GedcomRecord::accessFilter(), $offset, $limit);
}
/**
@@ -237,7 +250,7 @@ class SearchService
$this->whereTrees($query, 's_file', $trees);
$this->whereSearch($query, 's_gedcom', $search);
- return $this->paginateQuery($query, Source::rowMapper(), GedcomRecord::accessFilter(), $offset, $limit);
+ return $this->paginateQuery($query, $this->sourceRowMapper(), GedcomRecord::accessFilter(), $offset, $limit);
}
/**
@@ -258,7 +271,7 @@ class SearchService
$this->whereTrees($query, 's_file', $trees);
$this->whereSearch($query, 's_name', $search);
- return $this->paginateQuery($query, Source::rowMapper(), GedcomRecord::accessFilter(), $offset, $limit);
+ return $this->paginateQuery($query, $this->sourceRowMapper(), GedcomRecord::accessFilter(), $offset, $limit);
}
/**
@@ -279,7 +292,7 @@ class SearchService
$this->whereTrees($query, 'o_file', $trees);
$this->whereSearch($query, 'o_gedcom', $search);
- return $this->paginateQuery($query, GedcomRecord::rowMapper(), GedcomRecord::accessFilter(), $offset, $limit);
+ return $this->paginateQuery($query, $this->submitterRowMapper(), GedcomRecord::accessFilter(), $offset, $limit);
}
/**
@@ -695,7 +708,7 @@ class SearchService
return $query
->get()
->each($this->rowLimiter())
- ->map(Individual::rowMapper())
+ ->map($this->individualRowMapper())
->filter(GedcomRecord::accessFilter())
->filter(static function (Individual $individual) use ($fields): bool {
// Check for searches which were only partially matched by SQL
@@ -825,7 +838,7 @@ class SearchService
return $query
->get()
->each($this->rowLimiter())
- ->map(Individual::rowMapper())
+ ->map($this->individualRowMapper())
->filter(GedcomRecord::accessFilter());
}
@@ -918,6 +931,31 @@ class SearchService
$query->whereIn($tree_id_field, $tree_ids);
}
+
+ /**
+ * Find the media object that uses a particular media file.
+ *
+ * @param string $file
+ *
+ * @return Media[]
+ */
+ public function findMediaObjectsForMediaFile(string $file): array
+ {
+ return DB::table('media')
+ ->join('media_file', static function (JoinClause $join): void {
+ $join
+ ->on('media_file.m_file', '=', 'media.m_file')
+ ->on('media_file.m_id', '=', 'media.m_id');
+ })
+ ->join('gedcom_setting', 'media.m_file', '=', 'gedcom_setting.gedcom_id')
+ ->where(new Expression('setting_value || multimedia_file_refn'), '=', $file)
+ ->select(['media.*'])
+ ->distinct()
+ ->get()
+ ->map($this->mediaRowMapper())
+ ->all();
+ }
+
/**
* A closure to filter records by privacy-filtered GEDCOM data.
*
@@ -964,4 +1002,102 @@ class SearchService
}
};
}
+
+ /**
+ * Convert a row from any tree in the families table into a family object.
+ *
+ * @return Closure
+ */
+ private function familyRowMapper(): Closure
+ {
+ return function (stdClass $row): Family {
+ $tree = $this->tree_service->find((int) $row->f_file);
+
+ return Family::getInstance($row->f_id, $tree, $row->f_gedcom);
+ };
+ }
+
+ /**
+ * Convert a row from any tree in the individuals table into an individual object.
+ *
+ * @return Closure
+ */
+ private function individualRowMapper(): Closure
+ {
+ return function (stdClass $row): Individual {
+ $tree = $this->tree_service->find((int) $row->i_file);
+
+ return Individual::getInstance($row->i_id, $tree, $row->i_gedcom);
+ };
+ }
+
+ /**
+ * Convert a row from any tree in the media table into an media object.
+ *
+ * @return Closure
+ */
+ private function mediaRowMapper(): Closure
+ {
+ return function (stdClass $row): Media {
+ $tree = $this->tree_service->find((int) $row->m_file);
+
+ return Media::getInstance($row->m_id, $tree, $row->m_gedcom);
+ };
+ }
+
+ /**
+ * Convert a row from any tree in the other table into a note object.
+ *
+ * @return Closure
+ */
+ private function noteRowMapper(): Closure
+ {
+ return function (stdClass $row): Note {
+ $tree = $this->tree_service->find((int) $row->o_file);
+
+ return Note::getInstance($row->o_id, $tree, $row->o_gedcom);
+ };
+ }
+
+ /**
+ * Convert a row from any tree in the other table into a repository object.
+ *
+ * @return Closure
+ */
+ private function repositoryRowMapper(): Closure
+ {
+ return function (stdClass $row): Repository {
+ $tree = $this->tree_service->find((int) $row->o_file);
+
+ return Repository::getInstance($row->o_id, $tree, $row->o_gedcom);
+ };
+ }
+
+ /**
+ * Convert a row from any tree in the sources table into a source object.
+ *
+ * @return Closure
+ */
+ private function sourceRowMapper(): Closure
+ {
+ return function (stdClass $row): Source {
+ $tree = $this->tree_service->find((int) $row->s_file);
+
+ return Source::getInstance($row->s_id, $tree, $row->s_gedcom);
+ };
+ }
+
+ /**
+ * Convert a row from any tree in the other table into a submitter object.
+ *
+ * @return Closure
+ */
+ private function submitterRowMapper(): Closure
+ {
+ return function (stdClass $row): GedcomRecord {
+ $tree = $this->tree_service->find((int) $row->o_file);
+
+ return GedcomRecord::getInstance($row->o_id, $tree, $row->o_gedcom);
+ };
+ }
}
diff --git a/app/Source.php b/app/Source.php
index fba2fbfea1..13a2b13a37 100644
--- a/app/Source.php
+++ b/app/Source.php
@@ -37,12 +37,14 @@ class Source extends GedcomRecord
/**
* A closure which will create a record from a database row.
*
+ * @param Tree $tree
+ *
* @return Closure
*/
- public static function rowMapper(): Closure
+ public static function rowMapper(Tree $tree): Closure
{
- return static function (stdClass $row): Source {
- return Source::getInstance($row->s_id, Tree::findById((int) $row->s_file), $row->s_gedcom);
+ return static function (stdClass $row) use ($tree): Source {
+ return Source::getInstance($row->s_id, $tree, $row->s_gedcom);
};
}
diff --git a/app/Statistics/Repository/FamilyRepository.php b/app/Statistics/Repository/FamilyRepository.php
index aa3474e0a6..466d93bcbe 100644
--- a/app/Statistics/Repository/FamilyRepository.php
+++ b/app/Statistics/Repository/FamilyRepository.php
@@ -79,7 +79,7 @@ class FamilyRepository
}
/** @var Family $family */
- $family = Family::rowMapper()($row);
+ $family = Family::rowMapper($this->tree)($row);
if (!$family->canShow()) {
return I18N::translate('This information is private and cannot be shown.');
@@ -160,7 +160,7 @@ class FamilyRepository
->select(['families.*'])
->limit($total)
->get()
- ->map(Family::rowMapper())
+ ->map(Family::rowMapper($this->tree))
->filter(GedcomRecord::accessFilter())
->map(static function (Family $family): array {
$count = 0;
@@ -242,7 +242,7 @@ class FamilyRepository
->where('f_file', '=', $this->tree->id())
->where('f_numchil', '=', 0)
->get()
- ->map(Family::rowMapper())
+ ->map(Family::rowMapper($this->tree))
->filter(GedcomRecord::accessFilter());
$top10 = [];
@@ -619,7 +619,7 @@ class FamilyRepository
->orderBy('f_numchil', 'DESC')
->limit($total)
->get()
- ->map(Family::rowMapper())
+ ->map(Family::rowMapper($this->tree))
->filter(GedcomRecord::accessFilter())
->map(static function (Family $family): array {
return [
@@ -1287,7 +1287,7 @@ class FamilyRepository
->select(['families.*'])
->take($total)
->get()
- ->map(Family::rowMapper())
+ ->map(Family::rowMapper($this->tree))
->filter(GedcomRecord::accessFilter())
->map(function (Family $family) use ($age_dir): array {
$husb_birt_jd = $family->husband()->getBirthDate()->minimumJulianDay();
diff --git a/app/Statistics/Repository/IndividualRepository.php b/app/Statistics/Repository/IndividualRepository.php
index e57ff2834a..0ea0e26bc9 100644
--- a/app/Statistics/Repository/IndividualRepository.php
+++ b/app/Statistics/Repository/IndividualRepository.php
@@ -830,7 +830,7 @@ class IndividualRepository implements IndividualRepositoryInterface
}
/** @var Individual $individual */
- $individual = Individual::rowMapper()($row);
+ $individual = Individual::rowMapper($this->tree)($row);
if (!$individual->canShow()) {
return I18N::translate('This information is private and cannot be shown.');
@@ -981,7 +981,7 @@ class IndividualRepository implements IndividualRepositoryInterface
$top10 = [];
foreach ($rows as $row) {
/** @var Individual $individual */
- $individual = Individual::rowMapper()($row);
+ $individual = Individual::rowMapper($this->tree)($row);
if ($individual->canShow()) {
$top10[] = [
@@ -1123,7 +1123,7 @@ class IndividualRepository implements IndividualRepositoryInterface
->select(['individuals.*'])
->take($total)
->get()
- ->map(Individual::rowMapper())
+ ->map(Individual::rowMapper($this->tree))
->filter(GedcomRecord::accessFilter())
->map(function (Individual $individual): array {
return [
diff --git a/app/Tree.php b/app/Tree.php
index 6357fac388..cd1e7800aa 100644
--- a/app/Tree.php
+++ b/app/Tree.php
@@ -123,21 +123,6 @@ class Tree
}
/**
- * Find the tree with a specific ID.
- *
- * @param int $tree_id
- *
- * @return Tree
- * @deprecated
- */
- public static function findById(int $tree_id): Tree
- {
- return app(TreeService::class)->all()->first(static function (Tree $tree) use ($tree_id): bool {
- return $tree->id() === $tree_id;
- });
- }
-
- /**
* Set the tree’s configuration settings.
*
* @param string $setting_name
diff --git a/tests/app/Http/Controllers/Admin/FixLevel0MediaControllerTest.php b/tests/app/Http/Controllers/Admin/FixLevel0MediaControllerTest.php
index 1199d0e893..26c4307202 100644
--- a/tests/app/Http/Controllers/Admin/FixLevel0MediaControllerTest.php
+++ b/tests/app/Http/Controllers/Admin/FixLevel0MediaControllerTest.php
@@ -39,9 +39,11 @@ class FixLevel0MediaControllerTest extends TestCase
*/
public function testFixLevel0Media(): void
{
- $controller = new FixLevel0MediaController(new DatatablesService());
- $request = self::createRequest();
- $response = $controller->fixLevel0Media($request);
+ $datatables_service = new DatatablesService();
+ $tree_service = new TreeService();
+ $controller = new FixLevel0MediaController($datatables_service, $tree_service);
+ $request = self::createRequest();
+ $response = $controller->fixLevel0Media($request);
$this->assertSame(StatusCodeInterface::STATUS_OK, $response->getStatusCode());
}
@@ -53,7 +55,7 @@ class FixLevel0MediaControllerTest extends TestCase
{
$tree_service = new TreeService();
$tree = $tree_service->create('name', 'title');
- $controller = new FixLevel0MediaController(new DatatablesService());
+ $controller = new FixLevel0MediaController(new DatatablesService(), $tree_service);
$request = self::createRequest(RequestMethodInterface::METHOD_POST, [], [
'tree_id' => $tree->id(),
'fact_id' => '',
@@ -73,7 +75,7 @@ class FixLevel0MediaControllerTest extends TestCase
$datatables_service = new DatatablesService();
$tree_service = new TreeService();
$tree = $tree_service->create('name', 'title');
- $controller = new FixLevel0MediaController($datatables_service);
+ $controller = new FixLevel0MediaController($datatables_service, $tree_service);
$request = self::createRequest(RequestMethodInterface::METHOD_GET, ['tree_id' => $tree->id()]);
$response = $controller->fixLevel0MediaData($request);
diff --git a/tests/app/Http/Controllers/Admin/ImportThumbnailsControllerTest.php b/tests/app/Http/Controllers/Admin/ImportThumbnailsControllerTest.php
index 47d491e28e..4a693ff833 100644
--- a/tests/app/Http/Controllers/Admin/ImportThumbnailsControllerTest.php
+++ b/tests/app/Http/Controllers/Admin/ImportThumbnailsControllerTest.php
@@ -21,6 +21,7 @@ namespace Fisharebest\Webtrees\Http\Controllers\Admin;
use Fig\Http\Message\StatusCodeInterface;
use Fisharebest\Webtrees\Services\PendingChangesService;
+use Fisharebest\Webtrees\Services\SearchService;
use Fisharebest\Webtrees\Services\TreeService;
use Fisharebest\Webtrees\TestCase;
use League\Flysystem\Filesystem;
@@ -41,8 +42,10 @@ class ImportThumbnailsControllerTest extends TestCase
public function testWebtrees1Thumbnails(): void
{
$tree_service = new TreeService();
+ $search_service = new SearchService($tree_service);
+ $tree_service = new TreeService();
$pending_changes_service = new PendingChangesService();
- $controller = new ImportThumbnailsController($pending_changes_service, $tree_service);
+ $controller = new ImportThumbnailsController($pending_changes_service, $search_service, $tree_service);
$request = self::createRequest();
$response = $controller->webtrees1Thumbnails($request);
@@ -55,8 +58,9 @@ class ImportThumbnailsControllerTest extends TestCase
public function testWebtrees1ThumbnailsAction(): void
{
$tree_service = new TreeService();
+ $search_service = new SearchService($tree_service);
$pending_changes_service = new PendingChangesService();
- $controller = new ImportThumbnailsController($pending_changes_service, $tree_service);
+ $controller = new ImportThumbnailsController($pending_changes_service, $search_service, $tree_service);
$request = self::createRequest()
->withParsedBody(['thumbnail' => 'foo', 'action' => '', 'xref' => [], 'ged' => []]);
$response = $controller->webtrees1ThumbnailsAction($request);
@@ -70,8 +74,9 @@ class ImportThumbnailsControllerTest extends TestCase
public function testWebtrees1ThumbnailsData(): void
{
$tree_service = new TreeService();
+ $search_service = new SearchService($tree_service);
$pending_changes_service = new PendingChangesService();
- $controller = new ImportThumbnailsController($pending_changes_service, $tree_service);
+ $controller = new ImportThumbnailsController($pending_changes_service, $search_service, $tree_service);
$request = self::createRequest()
->withQueryParams(['start' => '0', 'length' => '10', 'search' => ['value' => ''], 'draw' => '1'])
->withAttribute('filesystem.data', new Filesystem(new MemoryAdapter()));
diff --git a/tests/app/Http/Controllers/Admin/MediaControllerTest.php b/tests/app/Http/Controllers/Admin/MediaControllerTest.php
index 6a5d9d1b80..93e2ae0e52 100644
--- a/tests/app/Http/Controllers/Admin/MediaControllerTest.php
+++ b/tests/app/Http/Controllers/Admin/MediaControllerTest.php
@@ -23,6 +23,7 @@ use Fig\Http\Message\RequestMethodInterface;
use Fig\Http\Message\StatusCodeInterface;
use Fisharebest\Webtrees\Services\DatatablesService;
use Fisharebest\Webtrees\Services\MediaFileService;
+use Fisharebest\Webtrees\Services\TreeService;
use Fisharebest\Webtrees\TestCase;
use League\Flysystem\Adapter\NullAdapter;
use League\Flysystem\Filesystem;
@@ -43,8 +44,9 @@ class MediaControllerTest extends TestCase
{
$datatables_service = new DatatablesService();
$media_file_service = new MediaFileService();
+ $tree_service = new TreeService();
$data_filesystem = new Filesystem(new NullAdapter());
- $controller = new MediaController($datatables_service, $media_file_service);
+ $controller = new MediaController($datatables_service, $media_file_service, $tree_service);
$request = self::createRequest()
->withAttribute('filesystem.data', $data_filesystem)
->withAttribute('filesystem.data.name', 'data/');
@@ -60,8 +62,9 @@ class MediaControllerTest extends TestCase
{
$datatables_service = new DatatablesService();
$media_file_service = new MediaFileService();
+ $tree_service = new TreeService();
$data_filesystem = new Filesystem(new NullAdapter());
- $controller = new MediaController($datatables_service, $media_file_service);
+ $controller = new MediaController($datatables_service, $media_file_service, $tree_service);
$request = self::createRequest(RequestMethodInterface::METHOD_GET, [
'files' => 'local',
'media_folder' => '',
@@ -84,8 +87,9 @@ class MediaControllerTest extends TestCase
{
$datatables_service = new DatatablesService();
$media_file_service = new MediaFileService();
+ $tree_service = new TreeService();
$data_filesystem = new Filesystem(new NullAdapter());
- $controller = new MediaController($datatables_service, $media_file_service);
+ $controller = new MediaController($datatables_service, $media_file_service, $tree_service);
$request = self::createRequest(RequestMethodInterface::METHOD_GET, [
'files' => 'local',
'media_folder' => '',
@@ -108,8 +112,9 @@ class MediaControllerTest extends TestCase
{
$datatables_service = new DatatablesService();
$media_file_service = new MediaFileService();
+ $tree_service = new TreeService();
$data_filesystem = new Filesystem(new NullAdapter());
- $controller = new MediaController($datatables_service, $media_file_service);
+ $controller = new MediaController($datatables_service, $media_file_service, $tree_service);
$request = self::createRequest(RequestMethodInterface::METHOD_GET, [
'files' => 'local',
'media_folder' => '',
@@ -132,8 +137,9 @@ class MediaControllerTest extends TestCase
{
$datatables_service = new DatatablesService();
$media_file_service = new MediaFileService();
+ $tree_service = new TreeService();
$data_filesystem = new Filesystem(new NullAdapter());
- $controller = new MediaController($datatables_service, $media_file_service);
+ $controller = new MediaController($datatables_service, $media_file_service, $tree_service);
$request = self::createRequest()->withAttribute('filesystem.data', $data_filesystem);
$response = $controller->upload($request);
@@ -147,8 +153,9 @@ class MediaControllerTest extends TestCase
{
$datatables_service = new DatatablesService();
$media_file_service = new MediaFileService();
+ $tree_service = new TreeService();
$data_filesystem = new Filesystem(new NullAdapter());
- $controller = new MediaController($datatables_service, $media_file_service);
+ $controller = new MediaController($datatables_service, $media_file_service, $tree_service);
$request = self::createRequest()->withAttribute('filesystem.data', $data_filesystem);
$response = $controller->uploadAction($request);
diff --git a/tests/app/Services/SearchServiceTest.php b/tests/app/Services/SearchServiceTest.php
index 35b3b31691..f6a345f1fd 100644
--- a/tests/app/Services/SearchServiceTest.php
+++ b/tests/app/Services/SearchServiceTest.php
@@ -36,7 +36,8 @@ class SearchServiceTest extends TestCase
*/
public function testSearchesReturnCollections(): void
{
- $search_service = new SearchService();
+ $tree_service = new TreeService();
+ $search_service = new SearchService($tree_service);
$tree = $this->importTree('demo.ged');
$result = $search_service->searchFamilies([$tree], ['windsor']);