Skip to content

Commit a72066e

Browse files
authored
Merge pull request #1585 from craftcms/feature/1572-relation-field-elements-matching
Feature/1572 relation field elements matching
2 parents a45830a + 5085685 commit a72066e

File tree

15 files changed

+502
-236
lines changed

15 files changed

+502
-236
lines changed

CHANGELOG.md

+4
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
# Release Notes for Feed Me
22

3+
## Unreleased
4+
5+
- Improved the experience of mapping relational fields with individual field instances in Craft 5. ([#1585](https://github.com/craftcms/feed-me/issues/1585))
6+
37
## 6.6.1 - 2024-12-01
48

59
- Fixed a PHP error that could occur if you did not have Commerce installed when running a feed. ([#1556](https://github.com/craftcms/feed-me/issues/1556))

docs/.vitepress/utils.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ function renderInlineCode(tokens, idx, options, env, renderer) {
77
var token = tokens[idx];
88

99
return `<code v-pre ${renderer.renderAttrs(token)}>${escapeHtml(
10-
tokens[idx].content,
10+
tokens[idx].content
1111
)}</code>`;
1212
}
1313

src/fields/Categories.php

+44
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,16 @@
55
use Cake\Utility\Hash;
66
use Craft;
77
use craft\base\Element as BaseElement;
8+
use craft\elements\Category;
89
use craft\elements\Category as CategoryElement;
910
use craft\elements\conditions\ElementConditionInterface;
1011
use craft\feedme\base\Field;
1112
use craft\feedme\base\FieldInterface;
1213
use craft\feedme\helpers\DataHelper;
14+
use craft\feedme\helpers\FieldHelper;
15+
use craft\feedme\models\FeedModel;
1316
use craft\feedme\Plugin;
17+
use craft\fields\BaseRelationField;
1418
use craft\fields\Categories as CategoriesField;
1519
use craft\helpers\Db;
1620
use craft\helpers\ElementHelper;
@@ -215,6 +219,46 @@ public function parseField(): mixed
215219
return $foundElements;
216220
}
217221

222+
/**
223+
* Returns an array of custom fields that can be used when querying for matching categories.
224+
*
225+
* If a field is passed, use the field layout linked to the source (category group) selected in the Categories field's settings.
226+
* If the source is native (it's a category group), only return the custom fields from its layout.
227+
* If the source is custom, return all the fields in the installation.
228+
*
229+
* @param FeedModel $feed
230+
* @param BaseRelationField|null $field
231+
* @return array
232+
*/
233+
public static function getMatchFields(FeedModel $feed, ?BaseRelationField $field = null): array
234+
{
235+
// The field will be null e.g. when importing into a categories group with maintain hierarchy turned on;
236+
// in that case, there's the option to select a parent;
237+
// the parent is serviced by the categories field markup too, but it doesn't tie into a custom field per se;
238+
if ($field === null) {
239+
$categoryGroup = Craft::$app->getCategories()->getGroupById($feed->elementGroup[Category::class]);
240+
if (!$categoryGroup) {
241+
return FieldHelper::getAllUniqueIdFields();
242+
}
243+
$fieldLayout = Craft::$app->getFields()->getLayoutById($categoryGroup->fieldLayoutId);
244+
if (!$fieldLayout) {
245+
return FieldHelper::getAllUniqueIdFields();
246+
}
247+
248+
return array_filter($fieldLayout->getCustomFields(), fn($field) => FieldHelper::fieldCanBeUniqueId($field));
249+
} else {
250+
// if the Categories field has only custom source - we have no choice but return all the field
251+
if (FieldHelper::fieldHasOnlyCustomSources($field)) {
252+
return FieldHelper::getAllUniqueIdFields();
253+
}
254+
// otherwise get the layout for the group selected in the field's settings
255+
return array_filter(
256+
FieldHelper::getElementLayoutByField($field::class, $field),
257+
fn($field) => FieldHelper::fieldCanBeUniqueId($field)
258+
);
259+
}
260+
}
261+
218262
// Private Methods
219263
// =========================================================================
220264

src/fields/Entries.php

+68
Original file line numberDiff line numberDiff line change
@@ -6,17 +6,22 @@
66
use Craft;
77
use craft\base\Element as BaseElement;
88
use craft\elements\conditions\ElementConditionInterface;
9+
use craft\elements\Entry;
910
use craft\elements\Entry as EntryElement;
1011
use craft\errors\ElementNotFoundException;
1112
use craft\feedme\base\Field;
1213
use craft\feedme\base\FieldInterface;
1314
use craft\feedme\helpers\DataHelper;
15+
use craft\feedme\helpers\FieldHelper;
16+
use craft\feedme\models\FeedModel;
1417
use craft\feedme\Plugin;
18+
use craft\fields\BaseRelationField;
1519
use craft\fields\Entries as EntriesField;
1620
use craft\helpers\Db;
1721
use craft\helpers\ElementHelper;
1822
use craft\helpers\Json;
1923
use craft\services\ElementSources;
24+
use Illuminate\Support\Collection;
2025
use Throwable;
2126
use yii\base\Exception;
2227

@@ -240,6 +245,69 @@ public function parseField(): mixed
240245
return $foundElements;
241246
}
242247

248+
/**
249+
* Returns an array of custom fields that can be used when querying for matching entries.
250+
*
251+
* If a field is passed, use the field layouts linked to the sources allowed by the Entries field.
252+
* If all the sources are native (sections), then only fields from all those sections entry types field layouts will be returned.
253+
* If there's at least one custom source in the mix, the above list will be followed by a list of all the fields.
254+
* If only custom sources are selected, return all the fields in the installation.
255+
*
256+
* @param FeedModel $feed
257+
* @param BaseRelationField|null $field
258+
* @return array
259+
*/
260+
public static function getMatchFields(FeedModel $feed, ?BaseRelationField $field = null): array
261+
{
262+
// The field will be null e.g. when importing into a structure section and there's the option to select a parent
263+
// the parent is serviced by the entries field markup too, but it doesn't tie into a custom field per se;
264+
if ($field === null) {
265+
$entryType = Craft::$app->getEntries()->getEntryTypeById($feed->elementGroup[Entry::class]['entryType']);
266+
if (!$entryType) {
267+
return FieldHelper::getAllUniqueIdFields();
268+
}
269+
270+
$fieldLayout = Craft::$app->getFields()->getLayoutById($entryType->fieldLayoutId);
271+
if (!$fieldLayout) {
272+
return FieldHelper::getAllUniqueIdFields();
273+
}
274+
275+
return array_filter(
276+
$fieldLayout->getCustomFields(),
277+
fn($field) => FieldHelper::fieldCanBeUniqueId($field)
278+
);
279+
} else {
280+
// if the Entries field has only custom sources - we have no choice but return all the field
281+
if (FieldHelper::fieldHasOnlyCustomSources($field)) {
282+
return FieldHelper::getAllUniqueIdFields();
283+
}
284+
285+
// deal with the native sources - sections
286+
$sections = FieldHelper::getEntrySourcesByField($field);
287+
$entryTypes = [];
288+
foreach ($sections as $section) {
289+
$entryTypes = [...$entryTypes, ...$section->getEntryTypes()];
290+
}
291+
292+
$allowedFields = [];
293+
$entryTypes = Collection::make($entryTypes)->keyBy('id');
294+
295+
foreach ($entryTypes as $entryType) {
296+
$fieldLayout = Craft::$app->getFields()->getLayoutById($entryType->fieldLayoutId);
297+
$allowedFields = [...$allowedFields, ...$fieldLayout->getCustomFields()];
298+
}
299+
300+
// if there's a custom source in the mix, we should add all the fields too
301+
$customSources = array_filter($field['sources'], (fn(string $source) => str_starts_with($source, 'custom:')));
302+
303+
if (!empty($customSources)) {
304+
$allowedFields = [...$allowedFields, ...Craft::$app->getFields()->getAllFields()];
305+
}
306+
307+
return array_filter($allowedFields, fn($field) => FieldHelper::fieldCanBeUniqueId($field));
308+
}
309+
}
310+
243311

244312
// Private Methods
245313
// =========================================================================

src/fields/Users.php

+16
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,10 @@
1212
use craft\feedme\base\Field;
1313
use craft\feedme\base\FieldInterface;
1414
use craft\feedme\helpers\DataHelper;
15+
use craft\feedme\helpers\FieldHelper;
16+
use craft\feedme\models\FeedModel;
1517
use craft\feedme\Plugin;
18+
use craft\fields\BaseRelationField;
1619
use craft\fields\Users as UsersField;
1720
use craft\helpers\Db;
1821
use craft\helpers\ElementHelper;
@@ -209,6 +212,19 @@ public function parseField(): mixed
209212
return $foundElements;
210213
}
211214

215+
/**
216+
* Returns an array of custom fields that can be used when querying for matching users.
217+
* There's only one user layout, so the fields from it are returned.
218+
*
219+
* @param FeedModel $feed
220+
* @param BaseRelationField|null $field
221+
* @return array
222+
*/
223+
public static function getMatchFields(FeedModel $feed, ?BaseRelationField $field = null): array
224+
{
225+
return array_filter(FieldHelper::getUserLayoutByField(), fn($field) => FieldHelper::fieldCanBeUniqueId($field));
226+
}
227+
212228
// Private Methods
213229
// =========================================================================
214230

0 commit comments

Comments
 (0)