Merge branch '2.x' of https://github.com/farmOS/farmOS into AssetOwners
This commit is contained in:
commit
b8246e74bf
|
@ -0,0 +1,155 @@
|
|||
name: Run tests and delivery workflow
|
||||
on:
|
||||
schedule:
|
||||
- cron: '0 8 * * *' # Run at 8AM UTC.
|
||||
push:
|
||||
branches:
|
||||
- '2.x'
|
||||
- '2.x-**'
|
||||
tags:
|
||||
- '2.*'
|
||||
pull_request:
|
||||
branches:
|
||||
- '2.x'
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: Build Docker images
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout the repository
|
||||
uses: actions/checkout@v2
|
||||
- name: Set default FARMOS_REPO and FARMOS_VERSION.
|
||||
run: |
|
||||
echo "FARMOS_REPO=${GITHUB_REPOSITORY}" >> $GITHUB_ENV
|
||||
echo "FARMOS_VERSION=2.x" >> $GITHUB_ENV
|
||||
- name: Set FARMOS_VERSION for branch push event.
|
||||
if: github.event_name == 'push' && github.ref_type == 'branch'
|
||||
run: echo "FARMOS_VERSION=${GITHUB_REF:11}" >> $GITHUB_ENV
|
||||
- name: Set FARMOS_VERSION for tag push event.
|
||||
if: github.event_name == 'push' && github.ref_type == 'tag'
|
||||
run: echo "FARMOS_VERSION=${GITHUB_REF:10}" >> $GITHUB_ENV
|
||||
- name: Set FARMOS_VERSION and FARMOS_REPO for pull request event.
|
||||
if: github.event_name == 'pull_request'
|
||||
run: |
|
||||
echo "FARMOS_VERSION=${GITHUB_HEAD_REF}" >> $GITHUB_ENV
|
||||
echo "FARMOS_REPO=${{ github.event.pull_request.head.repo.full_name }}" >> $GITHUB_ENV
|
||||
- name: Build and save farmOS 2.x Docker image
|
||||
run: |
|
||||
docker build --build-arg FARMOS_REPO=https://github.com/${FARMOS_REPO} --build-arg FARMOS_VERSION=${FARMOS_VERSION} -t farmos/farmos:2.x docker
|
||||
docker save farmos/farmos:2.x > /tmp/farmos-2x.tar
|
||||
- name: Cache farmOS 2.x Docker image
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: /tmp/farmos-2x.tar
|
||||
key: farmos-2x-${{ github.run_id }}
|
||||
# This builds the dev Docker image using the specified FARMOS_VERSION,
|
||||
# but notably it does NOT override the default PROJECT_VERSION, so the
|
||||
# farmOS Composer project 2.x branch is always used.
|
||||
- name: Build and save farmOS 2.x-dev Docker image
|
||||
run: |
|
||||
docker build --build-arg FARMOS_REPO=https://github.com/${FARMOS_REPO} --build-arg FARMOS_VERSION=${FARMOS_VERSION} -t farmos/farmos:2.x-dev docker/dev
|
||||
docker save farmos/farmos:2.x-dev > /tmp/farmos-2x-dev.tar
|
||||
- name: Cache farmOS 2.x-dev Docker image
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: /tmp/farmos-2x-dev.tar
|
||||
key: farmos-2x-dev-${{ github.run_id }}
|
||||
outputs:
|
||||
farmos_version: ${{ env.FARMOS_VERSION }}
|
||||
sniff:
|
||||
name: Run PHP Codesniffer
|
||||
runs-on: ubuntu-latest
|
||||
needs: build
|
||||
steps:
|
||||
- name: Checkout the repository
|
||||
uses: actions/checkout@v2
|
||||
- name: Restore farmOS 2.x-dev Docker image from cache
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: /tmp/farmos-2x-dev.tar
|
||||
key: farmos-2x-dev-${{ github.run_id }}
|
||||
- name: Load farmos/farmos:2.x-dev image
|
||||
run: docker load < /tmp/farmos-2x-dev.tar
|
||||
- name: Run PHP CodeSniffer
|
||||
run: docker run farmos/farmos:2.x-dev phpcs /opt/drupal/web/profiles/farm
|
||||
test:
|
||||
name: Run PHPUnit tests
|
||||
runs-on: ubuntu-latest
|
||||
needs: build
|
||||
strategy:
|
||||
matrix:
|
||||
dbms:
|
||||
- pgsql
|
||||
- mariadb
|
||||
- sqlite
|
||||
include:
|
||||
- dbms: pgsql
|
||||
DB_URL: pgsql://farm:farm@db/farm
|
||||
processes: auto
|
||||
- dbms: mariadb
|
||||
DB_URL: mysql://farm:farm@db/farm
|
||||
processes: auto
|
||||
- dbms: sqlite
|
||||
DB_URL: sqlite://localhost/sites/default/files/db.sqlite
|
||||
processes: 1
|
||||
steps:
|
||||
- name: Print test matrix variables
|
||||
run: echo "matrix.dbms=${{ matrix.dbms }}, matrix.DB_URL=${{ matrix.DB_URL }}"
|
||||
- name: Checkout the repository
|
||||
uses: actions/checkout@v2
|
||||
- name: Restore farmOS 2.x-dev Docker image from cache
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: /tmp/farmos-2x-dev.tar
|
||||
key: farmos-2x-dev-${{ github.run_id }}
|
||||
- name: Load farmos/farmos:2.x-dev image
|
||||
run: docker load < /tmp/farmos-2x-dev.tar
|
||||
# Build a new docker-compose.yml file from docker-compose.testing.common + docker-compose.testing.{dbms}.yml.
|
||||
# Copy to the current directory so that farmOS volume mounts don't change to the docker/www folder.
|
||||
- name: Create docker-compose.yml
|
||||
env:
|
||||
DB_URL: ${{ matrix.DB_URL }}
|
||||
run: |
|
||||
cp docker/docker-compose.testing.* .
|
||||
docker-compose -f docker-compose.testing.common.yml -f docker-compose.testing.${{ matrix.dbms }}.yml config > docker-compose.yml
|
||||
- name: Start containers
|
||||
run: docker-compose up -d
|
||||
- name: Wait until www container is ready
|
||||
# The www-container-fs-ready file is only created once we expect the containers to be online
|
||||
# so waiting for that lets us know it is safe to start the tests
|
||||
run: until [ -f ./www/www-container-fs-ready ]; do sleep 0.1; done
|
||||
- name: Run PHPUnit tests
|
||||
run: docker-compose exec -u www-data -T www paratest --verbose=1 --processes=${{ matrix.processes }} /opt/drupal/web/profiles/farm
|
||||
- name: Test Drush site install with all modules
|
||||
run: docker-compose exec -u www-data -T www drush site-install --db-url=${{ matrix.DB_URL }} farm farm.modules='all'
|
||||
release:
|
||||
name: Create GitHub release
|
||||
if: github.event_name == 'push' && github.ref_type == 'tag'
|
||||
runs-on: ubuntu-latest
|
||||
needs:
|
||||
- build
|
||||
- sniff
|
||||
- test
|
||||
steps:
|
||||
- name: Set FARMOS_VERSION from previous output.
|
||||
run: echo "FARMOS_VERSION=${{ needs.build.outputs.farmos_version }}" >> $GITHUB_ENV
|
||||
- name: Restore farmOS 2.x Docker image from cache
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: /tmp/farmos-2x.tar
|
||||
key: farmos-2x-${{ github.run_id }}
|
||||
- name: Load farmos/farmos:2.x image
|
||||
run: docker load < /tmp/farmos-2x.tar
|
||||
- name: Run farmOS Docker container
|
||||
run: docker run --rm -v /tmp/farmOS:/opt/drupal farmos/farmos:2.x true
|
||||
- name: Create artifact
|
||||
run: cd /tmp && tar -czf farmOS-${FARMOS_VERSION}.tar.gz farmOS
|
||||
- name: Create GitHub release
|
||||
uses: softprops/action-gh-release@6034af24fba4e5a8e975aaa6056554efe4c794d0 #0.1.13
|
||||
with:
|
||||
body: |
|
||||
For full release notes, see [CHANGELOG.md](https://github.com/farmOS/farmOS/blob/${{ env.FARMOS_VERSION }}/CHANGELOG.md).
|
||||
files: /tmp/farmOS-${{ env.FARMOS_VERSION }}.tar.gz
|
||||
draft: false
|
||||
prerelease: false
|
|
@ -1,32 +0,0 @@
|
|||
name: Create 2.x release
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- '2.*'
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: Create Release
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@master
|
||||
- name: Set FARMOS_VERSION environment variable
|
||||
run: echo "FARMOS_VERSION=${GITHUB_REF:10}" >> $GITHUB_ENV
|
||||
# This builds the Docker image using the specified FARMOS_VERSION,
|
||||
# but notably it does NOT override the default PROJECT_VERSION, so the
|
||||
# farmOS Composer project 2.x branch is always used.
|
||||
- name: Build farmOS Docker image
|
||||
run: docker build --build-arg FARMOS_REPO=https://github.com/${GITHUB_REPOSITORY} --build-arg FARMOS_VERSION=${FARMOS_VERSION} -t farmos docker
|
||||
- name: Run farmOS Docker container
|
||||
run: docker run --rm -v /tmp/farmOS:/opt/drupal farmos true
|
||||
- name: Create artifact
|
||||
run: cd /tmp && tar -czf farmOS-${FARMOS_VERSION}.tar.gz farmOS
|
||||
- name: Create GitHub release
|
||||
uses: softprops/action-gh-release@6034af24fba4e5a8e975aaa6056554efe4c794d0 #0.1.13
|
||||
with:
|
||||
body: |
|
||||
For full release notes, see [CHANGELOG.md](https://github.com/farmOS/farmOS/blob/${{ env.FARMOS_VERSION }}/CHANGELOG.md).
|
||||
files: /tmp/farmOS-${{ env.FARMOS_VERSION }}.tar.gz
|
||||
draft: false
|
||||
prerelease: false
|
|
@ -1,80 +0,0 @@
|
|||
name: Run 2.x PHPUnit tests
|
||||
on:
|
||||
schedule:
|
||||
- cron: '0 8 * * *' # Run at 8AM UTC.
|
||||
push:
|
||||
branches:
|
||||
- '2.x'
|
||||
- '2.x-**'
|
||||
pull_request:
|
||||
branches:
|
||||
- '2.x'
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: Run PHPUnit tests
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
dbms:
|
||||
- pgsql
|
||||
- mariadb
|
||||
- sqlite
|
||||
include:
|
||||
- dbms: pgsql
|
||||
DB_URL: pgsql://farm:farm@db/farm
|
||||
processes: auto
|
||||
- dbms: mariadb
|
||||
DB_URL: mysql://farm:farm@db/farm
|
||||
processes: auto
|
||||
- dbms: sqlite
|
||||
DB_URL: sqlite://localhost/sites/default/files/db.sqlite
|
||||
processes: 1
|
||||
# Allow all three database tests to run even when one fails.
|
||||
# This is a temporary workaround for Issue #3241653: Occasional test
|
||||
# failures with SQLite: SQLSTATE[HY000]: General error: 5 database is
|
||||
# locked
|
||||
# @todo https://www.drupal.org/project/farm/issues/3241653
|
||||
fail-fast: false
|
||||
steps:
|
||||
- name: Print test matrix variables
|
||||
run: echo "matrix.dbms=${{ matrix.dbms }}, matrix.DB_URL=${{ matrix.DB_URL }}"
|
||||
- name: Checkout the repository
|
||||
uses: actions/checkout@v2
|
||||
- name: Set FARMOS_VERSION for push event.
|
||||
if: ${{ !github.event.pull_request }}
|
||||
run: |
|
||||
echo "FARMOS_VERSION=${GITHUB_REF:11}" >> $GITHUB_ENV
|
||||
echo "FARMOS_REPO=${GITHUB_REPOSITORY}" >> $GITHUB_ENV
|
||||
- name: Set FARMOS_VERSION for pull request event.
|
||||
if: ${{ github.event.pull_request }}
|
||||
run: |
|
||||
echo "FARMOS_VERSION=${GITHUB_HEAD_REF}" >> $GITHUB_ENV
|
||||
echo "FARMOS_REPO=${{ github.event.pull_request.head.repo.full_name }}" >> $GITHUB_ENV
|
||||
- name: Build farmOS 2.x Docker image
|
||||
run: docker build --build-arg FARMOS_REPO=https://github.com/${FARMOS_REPO} --build-arg FARMOS_VERSION=${FARMOS_VERSION} -t farmos/farmos:2.x docker
|
||||
# This builds the dev Docker image using the specified FARMOS_VERSION,
|
||||
# but notably it does NOT override the default PROJECT_VERSION, so the
|
||||
# farmOS Composer project 2.x branch is always used.
|
||||
- name: Build farmOS 2.x-dev Docker image
|
||||
run: docker build --build-arg FARMOS_REPO=https://github.com/${FARMOS_REPO} --build-arg FARMOS_VERSION=${FARMOS_VERSION} -t farmos/farmos:2.x-dev docker/dev
|
||||
# Build a new docker-compose.yml file from docker-compose.testing.common + docker-compose.testing.{dbms}.yml.
|
||||
# Copy to the current directory so that farmOS volume mounts don't change to the docker/www folder.
|
||||
- name: Create docker-compose.yml
|
||||
env:
|
||||
DB_URL: ${{ matrix.DB_URL }}
|
||||
run: |
|
||||
cp docker/docker-compose.testing.* .
|
||||
docker-compose -f docker-compose.testing.common.yml -f docker-compose.testing.${{ matrix.dbms }}.yml config > docker-compose.yml
|
||||
- name: Start containers
|
||||
run: docker-compose up -d
|
||||
- name: Wait until www container is ready
|
||||
# The www-container-fs-ready file is only created once we expect the containers to be online
|
||||
# so waiting for that lets us know it is safe to start the tests
|
||||
run: until [ -f ./www/www-container-fs-ready ]; do sleep 0.1; done
|
||||
- name: Run PHP CodeSniffer
|
||||
run: docker-compose exec -u www-data -T www phpcs /opt/drupal/web/profiles/farm
|
||||
- name: Run PHPUnit tests
|
||||
run: docker-compose exec -u www-data -T www paratest --verbose=1 --processes=${{ matrix.processes }} /opt/drupal/web/profiles/farm
|
||||
- name: Test Drush site install with all modules
|
||||
run: docker-compose exec -u www-data -T www drush site-install --db-url=${{ matrix.DB_URL }} farm farm.modules='all'
|
32
CHANGELOG.md
32
CHANGELOG.md
|
@ -7,6 +7,35 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||
|
||||
## [Unreleased]
|
||||
|
||||
### Changed
|
||||
|
||||
- [Issue #3275161: Allow IMG tags in default text format](https://www.drupal.org/project/farm/issues/3275161)
|
||||
- [Update toolbar logo spacing for gin beta #527](https://github.com/farmOS/farmOS/pull/527)
|
||||
|
||||
### Fixed
|
||||
|
||||
- [Do not check php-geos requirement in the update phase #526](https://github.com/farmOS/farmOS/pull/526)
|
||||
|
||||
### Security
|
||||
|
||||
- Update Drupal core to 9.3.12 for [SA-CORE-2022-008](https://www.drupal.org/sa-core-2022-008) and
|
||||
[SA-CORE-2022-009](https://www.drupal.org/sa-core-2022-009).
|
||||
|
||||
## [2.0.0-beta4] 2022-04-13
|
||||
|
||||
### Added
|
||||
|
||||
- [Link from entities to their referenced terms and show entity views on taxonomy terms #458](https://github.com/farmOS/farmOS/pull/458).
|
||||
- [Encourage GEOS PHP extension use #521](https://github.com/farmOS/farmOS/pull/521)
|
||||
|
||||
### Changed
|
||||
|
||||
- Update [farmOS-map](https://github.com/farmOS/farmOS-map) to [v2.0.4](https://github.com/farmOS/farmOS-map/releases/tag/v2.0.4).
|
||||
- [Issue #3270561: Upgrade to gin beta](https://www.drupal.org/project/farm/issues/3270561)
|
||||
- [Separate Docker image build from testing jobs in run-test.yml workflow #522](https://github.com/farmOS/farmOS/pull/522)
|
||||
- [Merge test and release workflows into a unified delivery workflow #523](https://github.com/farmOS/farmOS/pull/523)
|
||||
- [Improve fields documentation #505](https://github.com/farmOS/farmOS/pull/505)
|
||||
|
||||
### Fixed
|
||||
|
||||
- [Only require a name to build map popups #515](https://github.com/farmOS/farmOS/pull/515)
|
||||
|
@ -160,7 +189,8 @@ moving forward.
|
|||
Drupal 7, which required a complete refactor of the codebase. By comparison,
|
||||
updating from Drupal 9 to 10 will simply involve updating deprecated code.
|
||||
|
||||
[Unreleased]: https://github.com/farmOS/farmOS/compare/2.0.0-beta3...HEAD
|
||||
[Unreleased]: https://github.com/farmOS/farmOS/compare/2.0.0-beta4...HEAD
|
||||
[2.0.0-beta4]: https://github.com/farmOS/farmOS/releases/tag/2.0.0-beta4
|
||||
[2.0.0-beta3]: https://github.com/farmOS/farmOS/releases/tag/2.0.0-beta3
|
||||
[2.0.0-beta2]: https://github.com/farmOS/farmOS/releases/tag/2.0.0-beta2
|
||||
[2.0.0-beta1]: https://github.com/farmOS/farmOS/releases/tag/2.0.0-beta1
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
"require": {
|
||||
"cweagans/composer-patches": "^1.6",
|
||||
"drupal/admin_toolbar": "^2.4",
|
||||
"drupal/core": "9.3.9",
|
||||
"drupal/core": "9.3.12",
|
||||
"drupal/config_update": "^1.7",
|
||||
"drupal/csv_serialization": "^2.0",
|
||||
"drupal/date_popup": "^1.1",
|
||||
|
@ -30,7 +30,7 @@
|
|||
"drupal/exif_orientation": "^1.1",
|
||||
"drupal/fraction": "^2.0",
|
||||
"drupal/geofield": "^1.33",
|
||||
"drupal/gin": "3.0-alpha37",
|
||||
"drupal/gin": "^3.0@beta",
|
||||
"drupal/inline_entity_form": "^1.0@RC",
|
||||
"drupal/inspire_tree": "^1.0",
|
||||
"drupal/jsonapi_extras": "^3.15",
|
||||
|
@ -60,9 +60,6 @@
|
|||
"drupal/entity": {
|
||||
"Issue #3206703: Provide reverse relationships for bundle plugin entity_reference fields.": "https://www.drupal.org/files/issues/2021-05-18/3206703-7.patch"
|
||||
},
|
||||
"drupal/gin": {
|
||||
"Issue #3245203: Sticky region has inconsistent z-index.": "https://www.drupal.org/files/issues/2021-10-21/3245203-alpha37-3.patch"
|
||||
},
|
||||
"drupal/jsonapi_schema": {
|
||||
"Issue #3256795: Float fields have a null schema": "https://www.drupal.org/files/issues/2022-01-03/3256795-4.patch",
|
||||
"Issue #3246251: Change format utc-millisec to date-time": "https://www.drupal.org/files/issues/2021-10-27/3246251-2.patch"
|
||||
|
|
|
@ -7,10 +7,10 @@
|
|||
"type": "package",
|
||||
"package": {
|
||||
"name": "farmos/farmos-map",
|
||||
"version": "2.0.3",
|
||||
"version": "2.0.4",
|
||||
"type": "drupal-library",
|
||||
"dist": {
|
||||
"url": "https://github.com/farmOS/farmOS-map/releases/download/v2.0.2/v2.0.2-dist.zip",
|
||||
"url": "https://github.com/farmOS/farmOS-map/releases/download/v2.0.4/v2.0.4-dist.zip",
|
||||
"type": "zip"
|
||||
},
|
||||
"extra": {
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
{
|
||||
"require": {
|
||||
"cweagans/composer-patches": "^1.7",
|
||||
"drupal/core-composer-scaffold": "9.3.9"
|
||||
"drupal/core-composer-scaffold": "9.3.12"
|
||||
},
|
||||
"require-dev": {
|
||||
"brianium/paratest": "^4",
|
||||
"drupal/core-dev": "9.3.9",
|
||||
"drupal/core-dev": "9.3.12",
|
||||
"phpspec/prophecy-phpunit": "^2",
|
||||
"symfony/finder": "^4.0"
|
||||
},
|
||||
|
|
|
@ -28,4 +28,7 @@ services:
|
|||
|
||||
# Enable this service when executing javascript tests.
|
||||
# chrome:
|
||||
# image: selenium/standalone-chrome:latest
|
||||
|
||||
# Tests are failing on later versions of this image.
|
||||
# See https://github.com/farmOS/farmOS/issues/514
|
||||
# image: selenium/standalone-chrome:4.1.2-20220217
|
||||
|
|
|
@ -10,4 +10,6 @@ services:
|
|||
XDEBUG_MODE: 'off'
|
||||
|
||||
chrome:
|
||||
image: selenium/standalone-chrome:latest
|
||||
# Tests are failing on later versions of this image.
|
||||
# See https://github.com/farmOS/farmOS/issues/514
|
||||
image: selenium/standalone-chrome:4.1.2-20220217
|
||||
|
|
|
@ -26,7 +26,9 @@ by adding the following container:
|
|||
|
||||
```yml
|
||||
chrome:
|
||||
image: selenium/standalone-chrome:latest
|
||||
# Tests are failing on later versions of this image.
|
||||
# See https://github.com/farmOS/farmOS/issues/514
|
||||
image: selenium/standalone-chrome:4.1.2-20220217
|
||||
```
|
||||
|
||||
## Faster testing without XDebug
|
||||
|
|
|
@ -15,7 +15,10 @@ If the field should be added to all bundles of a given entity type (eg: all log
|
|||
types), then they should be added as "base fields" via
|
||||
`hook_entity_base_field_info()`.
|
||||
|
||||
A `farm_field.factory` helper service is provided to make this easier:
|
||||
A `farm_field.factory` helper service is provided to make this easier. For more
|
||||
information on how this works, see [Field factory service](/development/module/services/#field-factory-service).
|
||||
|
||||
To get started, place the following in the `[modulename].module` file:
|
||||
|
||||
```php
|
||||
<?php
|
||||
|
@ -24,12 +27,14 @@ use Drupal\Core\Entity\EntityTypeInterface;
|
|||
|
||||
/**
|
||||
* Implements hook_entity_base_field_info().
|
||||
* NOTE: Replace 'mymodule' with the module name.
|
||||
*/
|
||||
function mymodule_entity_base_field_info(EntityTypeInterface $entity_type) {
|
||||
$fields = [];
|
||||
|
||||
// Add a new string field to Log entities.
|
||||
// 'log' specifies the entity type to apply to.
|
||||
if ($entity_type->id() == 'log') {
|
||||
// Options for the new field. See Field options below.
|
||||
$options = [
|
||||
'type' => 'string',
|
||||
'label' => t('My new field'),
|
||||
|
@ -39,6 +44,7 @@ function mymodule_entity_base_field_info(EntityTypeInterface $entity_type) {
|
|||
'view' => 10,
|
||||
],
|
||||
];
|
||||
// NOTE: Replace 'myfield' with the internal name of the field.
|
||||
$fields['myfield'] = \Drupal::service('farm_field.factory')->baseFieldDefinition($options);
|
||||
}
|
||||
|
||||
|
@ -56,10 +62,15 @@ then they should be added as "bundle fields" via
|
|||
deprecated in favor of a core Drupal hook in the future. See core issue:
|
||||
[https://www.drupal.org/node/2346347](https://www.drupal.org/node/2346347)
|
||||
|
||||
A `farm_field.factory` helper service is provided to make this easier. For more
|
||||
information on how this works, see [Field factory service](/development/module/services/#field-factory-service).
|
||||
|
||||
The format for bundle field definitions is identical to base field definitions
|
||||
(above), but the `bundleFieldDefinition()` method must be used instead of
|
||||
`baseFieldDefinition()`.
|
||||
|
||||
To get started, place the following in the `[modulename].module` file:
|
||||
|
||||
```php
|
||||
<?php
|
||||
|
||||
|
@ -67,12 +78,15 @@ use Drupal\Core\Entity\EntityTypeInterface;
|
|||
|
||||
/**
|
||||
* Implements hook_farm_entity_bundle_field_info().
|
||||
* NOTE: Replace 'mymodule' with the module name.
|
||||
*/
|
||||
function mymodule_farm_entity_bundle_field_info(EntityTypeInterface $entity_type, $bundle) {
|
||||
$fields = [];
|
||||
|
||||
// Add a new string field to Input Logs.
|
||||
// Add a new string field to Input Logs. 'log' specifies the entity type and
|
||||
// 'input' specifies the bundle.
|
||||
if ($entity_type->id() == 'log' && $bundle == 'input') {
|
||||
// Options for the new field. See Field options below.
|
||||
$options = [
|
||||
'type' => 'string',
|
||||
'label' => t('My new field'),
|
||||
|
@ -82,6 +96,7 @@ function mymodule_farm_entity_bundle_field_info(EntityTypeInterface $entity_type
|
|||
'view' => 10,
|
||||
],
|
||||
];
|
||||
// NOTE: Replace 'myfield' with the internal name of the field.
|
||||
$fields['myfield'] = \Drupal::service('farm_field.factory')->bundleFieldDefinition($options);
|
||||
}
|
||||
|
||||
|
@ -126,6 +141,10 @@ Existing options can be overridden or removed by editing/deleting the entities
|
|||
in the active configuration of the site. (**Warning** changing core types runs
|
||||
the risk of conflicting with future farmOS updates).
|
||||
|
||||
Note that the file name is important and must follow a specific pattern. This
|
||||
is generally in the form `[select_module_name].[select_field].[id].yml`. See
|
||||
the examples for more info.
|
||||
|
||||
### Examples:
|
||||
|
||||
#### Flag
|
||||
|
@ -140,11 +159,13 @@ dependencies:
|
|||
enforced:
|
||||
module:
|
||||
- my_module
|
||||
id: monitor
|
||||
label: Monitor
|
||||
id: organic
|
||||
label: Organic
|
||||
entity_types: null
|
||||
```
|
||||
|
||||
Note that the file name is in the form `farm_flag.flag.[id].yml`.
|
||||
|
||||
The most important parts are the `id`, which is a unique machine name for
|
||||
the flag, `label`, which is the human readable/translatable label that will be
|
||||
shown in the select field and other parts of the UI, and `entity_types`, which
|
||||
|
@ -194,6 +215,8 @@ id: field
|
|||
label: Field
|
||||
```
|
||||
|
||||
Note that the file name is in the form `farm_land.land_type.[id].yml`.
|
||||
|
||||
#### Structure type
|
||||
|
||||
The "Structure" module in farmOS provides a "Building" type like this:
|
||||
|
@ -211,6 +234,8 @@ id: building
|
|||
label: Building
|
||||
```
|
||||
|
||||
Note that the file name is in the form `farm_structure.structure_type.[id].yml`.
|
||||
|
||||
#### Lab test type
|
||||
|
||||
The "Lab test" module in farmOS provides a "Soil test" type like this:
|
||||
|
@ -228,6 +253,8 @@ id: soil
|
|||
label: Soil test
|
||||
```
|
||||
|
||||
Note that the file name is in the form `farm_lab_test.lab_test_type.[id].yml`.
|
||||
|
||||
#### ID tag type
|
||||
|
||||
ID tag types are similar to Flags, in that they have an `id` and `label`. They
|
||||
|
@ -237,7 +264,7 @@ certain types of assets.
|
|||
For example, an "Ear tag" type, provided by the "Animal asset" module, only
|
||||
applies to "Animal" assets:
|
||||
|
||||
`animal/config/install/farm_flag.flag.ear_tag.yml`
|
||||
`animal/config/install/farm_id_tag.id_tag.ear_tag.yml`
|
||||
|
||||
```yaml
|
||||
langcode: en
|
||||
|
@ -253,5 +280,7 @@ bundles:
|
|||
- animal
|
||||
```
|
||||
|
||||
Note that the file name is in the form `farm_flag.flag.ear_tag.[id].yml`.
|
||||
|
||||
If you want the tag type to apply to all assets, set `bundles: null`.
|
||||
(or can it just be omitted?)
|
||||
|
|
|
@ -74,6 +74,80 @@ $all_inventory = \Drupal::service('asset.inventory')->getInventory($asset);
|
|||
$gallons_of_fertilizer = \Drupal::service('asset.inventory')->getInventory($asset, 'volume', 'gallons');
|
||||
```
|
||||
|
||||
## Field factory service
|
||||
|
||||
**Service name**: `farm_field.factory`
|
||||
|
||||
The field factory service provides two methods to make the process of creating
|
||||
Drupal entity base and bundle field definitions easier and more consistent in
|
||||
farmOS. This is used by modules that add [fields](/development/module/fields)
|
||||
to [entity types](/development/module/entities).
|
||||
|
||||
Base fields are added to *all* bundles of a given entity type (eg: all logs).
|
||||
Bundle fields are only added to *specific* bundles (eg: only "Input" logs).
|
||||
|
||||
Using this service is optional. It simply generates instances of Drupal core's
|
||||
`BaseFieldDefinition` class or the Entity API module's `BundleFieldDefinition`
|
||||
class, with farmOS-specific opinions to help enforce some consistency among
|
||||
farmOS core and contrib modules. You can create instances of these field
|
||||
definition classes directly instead of using the farmOS field factory service.
|
||||
Or you can take the object produced by the service and customize it further
|
||||
using standard Drupal field definition methods. This service is provided only
|
||||
as a shortcut.
|
||||
|
||||
For more information on Drupal core's field definition API, see
|
||||
[Drupal FieldTypes, FieldWidgets and FieldFormatters](https://www.drupal.org/docs/drupal-apis/entity-api/fieldtypes-fieldwidgets-and-fieldformatters)
|
||||
|
||||
**Methods**:
|
||||
|
||||
`baseFieldDefinition($options)` - Generates a base field definition, given an
|
||||
array of options (see below).
|
||||
|
||||
`bundleFieldDefinition($options)` - Generates a bundle field definition, given
|
||||
an array of options (see below).
|
||||
|
||||
**Options**:
|
||||
|
||||
Both methods expect an array of field definition options. These include:
|
||||
|
||||
- `type` (required) - The field data type. Each type may require additional
|
||||
options. Supported types include:
|
||||
- `boolean` - True/false checkbox.
|
||||
- `entity_reference` - Reference other entities. Additional options:
|
||||
- `target_type` (required) - The entity type to reference (eg: `asset`,
|
||||
`log`, `plan`)
|
||||
- `target_bundle` (optional) - The allowed target bundle. For example,
|
||||
a `target_type` of `asset` and a `target_bundle` of `animal` would
|
||||
limit references to animal assets.
|
||||
- `auto_create` (optional) Only used when `target_type` is set to
|
||||
`taxonomy_term`. If `auto_create` is set, term references will be
|
||||
created automatically if the term does not exist.
|
||||
- `file` - File upload.
|
||||
- `fraction` - High-precision decimal number storage.
|
||||
- `geofield` - Geometry on a map.
|
||||
- `image` - Image upload.
|
||||
- `list_string` - Select list with allowed values. Additional options:
|
||||
- `allowed_values` - An associative array of allowed values.
|
||||
- `allowed_values_function` - The name of a function that returns an
|
||||
associative array of allowed values.
|
||||
- `string_long` - Unformatted text field of unlimited length.
|
||||
- `text_long` - Formatted text field of unlimited length.
|
||||
- `timestamp` - Date and time.
|
||||
- `label` - The field label.
|
||||
- `description` - The field description.
|
||||
- `required` - Whether the field is required.
|
||||
- `multiple` - Whether the field should allow multiple values. Defaults to
|
||||
`FALSE`.
|
||||
- `cardinality` - How many values are allowed (eg: `1` for single value
|
||||
fields, `-1` for unlimited values). This is an alternative to `multiple`,
|
||||
and will take precedence if it is set. Defaults to `1`.
|
||||
|
||||
Other options are available for more advanced use-cases. Refer to the
|
||||
[FarmFieldFactory](https://github.com/farmOS/farmOS/blob/2.x/modules/core/field/src/FarmFieldFactory.php)
|
||||
class to understand how they work.
|
||||
|
||||
For more information and example code, see [Adding fields](/development/module/fields).
|
||||
|
||||
## Group membership service
|
||||
|
||||
**Service name**: `group.membership`
|
||||
|
|
|
@ -29,7 +29,7 @@ There are three ways to zoom in/out:
|
|||
- On touch screens, you can "pinch zoom" using two fingers.
|
||||
- With a computer mouse, you can use the scroll wheel to zoom in/out (click
|
||||
on the map first to enable scroll zoom).
|
||||
- The plus (+) and minus (+) buttons in the top left of the map control zoom.
|
||||
- The plus (+) and minus (-) buttons in the top left of the map control zoom.
|
||||
|
||||
### Geolocating
|
||||
|
||||
|
|
|
@ -23,8 +23,9 @@ dependencies. The [farmOS Docker images](#farmos-in-docker) include these.
|
|||
- `realpath_cache_size=4096K`
|
||||
- `realpath_cache_ttl=3600`
|
||||
- **[PHP BCMath extension](https://www.php.net/manual/en/book.bc.php)** and
|
||||
**[GEOS](https://trac.osgeo.org/geos)** are recommended for more accurate
|
||||
geometric calculations.
|
||||
**[GEOS](https://trac.osgeo.org/geos)** are required for accurate geometric
|
||||
calculations. farmOS can be installed without these, but production usage
|
||||
without them is strongly discouraged.
|
||||
|
||||
### Database server
|
||||
|
||||
|
|
|
@ -30,7 +30,6 @@ function farm_modules() {
|
|||
'farm_plant' => t('Plant assets'),
|
||||
'farm_animal' => t('Animal assets'),
|
||||
'farm_equipment' => t('Equipment assets'),
|
||||
'farm_material' => t('Material assets'),
|
||||
'farm_structure' => t('Structure assets'),
|
||||
'farm_water' => t('Water assets'),
|
||||
'farm_activity' => t('Activity logs'),
|
||||
|
@ -46,6 +45,7 @@ function farm_modules() {
|
|||
],
|
||||
'optional' => [
|
||||
'farm_inventory' => t('Inventory management'),
|
||||
'farm_material' => t('Material assets'),
|
||||
'farm_seed' => t('Seed assets'),
|
||||
'farm_sensor' => t('Sensor assets'),
|
||||
'farm_compost' => t('Compost assets'),
|
||||
|
|
|
@ -351,7 +351,7 @@ class FarmFieldFactory implements FarmFieldFactoryInterface {
|
|||
'type' => 'entity_reference_label',
|
||||
'weight' => $options['weight']['view'] ?? 0,
|
||||
'settings' => [
|
||||
'link' => FALSE,
|
||||
'link' => TRUE,
|
||||
],
|
||||
];
|
||||
break;
|
||||
|
|
|
@ -11,7 +11,7 @@ filters:
|
|||
status: true
|
||||
weight: -10
|
||||
settings:
|
||||
allowed_html: '<a href hreflang> <em> <strong> <del> <cite> <blockquote cite> <code> <ul type> <ol start type=''1 A I''> <li> <dl> <dt> <dd> <h2 id=''jump-*''> <h3 id> <h4 id> <h5 id> <h6 id>'
|
||||
allowed_html: '<a href hreflang> <img src alt height width data-entity-type data-entity-uuid> <em> <strong> <del> <cite> <blockquote cite> <code> <ul type> <ol start type=''1 A I''> <li> <dl> <dt> <dd> <h2 id=''jump-*''> <h3 id> <h4 id> <h5 id> <h6 id>'
|
||||
filter_html_help: true
|
||||
filter_html_nofollow: false
|
||||
filter_autop:
|
||||
|
|
|
@ -0,0 +1,36 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Install, update and uninstall function for the farm_geo module.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Implements hook_requirements().
|
||||
*/
|
||||
function farm_geo_requirements($phase) {
|
||||
$requirements = [];
|
||||
|
||||
// Do not check requirements in the update phase.
|
||||
// The REQUIREMENT_WARNING severity prevents updates from being run.
|
||||
if ($phase == 'update') {
|
||||
return $requirements;
|
||||
}
|
||||
|
||||
// Check for php-geos extension.
|
||||
if (geoPHP::geosInstalled()) {
|
||||
$severity = REQUIREMENT_OK;
|
||||
$message = t('GEOS PHP extension installed');
|
||||
}
|
||||
else {
|
||||
$severity = REQUIREMENT_WARNING;
|
||||
$message = t('The GEOS PHP extension is not installed. While not required, it is strongly recommended for accurate geometry arithmetic. See %link for more information.', ['%link' => 'https://geophp.net/geos.html']);
|
||||
}
|
||||
$requirements['geos'] = [
|
||||
'title' => t('GEOS PHP extension'),
|
||||
'severity' => $severity,
|
||||
'value' => $message,
|
||||
];
|
||||
|
||||
return $requirements;
|
||||
}
|
|
@ -2,7 +2,7 @@ farm_settings.settings_page:
|
|||
base_route: farm_settings.settings_page
|
||||
route_name: farm_settings.settings_page
|
||||
title: 'Farm Info'
|
||||
weight: -1
|
||||
weight: -5
|
||||
|
||||
farm_settings.modules_form:
|
||||
base_route: farm_settings.settings_page
|
||||
|
|
|
@ -2,8 +2,9 @@
|
|||
Styling for the asset map_popup view mode page.
|
||||
*/
|
||||
|
||||
/* Remove the page background color. */
|
||||
body {
|
||||
/* Remove the page background color and body top padding. */
|
||||
body.path-asset {
|
||||
--ginHorizontalToolbarOffset: 0;
|
||||
background: unset !important;
|
||||
}
|
||||
|
||||
|
|
|
@ -3,10 +3,15 @@
|
|||
* Styling for farmOS toolbar.
|
||||
*/
|
||||
|
||||
/* Add padding to the wrapper around the logo. */
|
||||
.toolbar .toolbar-bar #toolbar-item-administration-tray .toolbar-logo {
|
||||
padding: .5em !important;
|
||||
}
|
||||
|
||||
/* Logo size and spacing. */
|
||||
.toolbar .toolbar-bar #toolbar-item-administration-tray .toolbar-logo img.toolbar-icon-home {
|
||||
max-width: 100px;
|
||||
margin: 40px auto;
|
||||
margin: 20px auto;
|
||||
}
|
||||
|
||||
/* Locations icon. */
|
||||
|
|
|
@ -27,10 +27,11 @@ function farm_ui_theme_install() {
|
|||
$gin_settings->set('preset_focus_color', 'orange');
|
||||
|
||||
// Use farmOS logo and favicon.
|
||||
$gin_settings->set('icon_default', FALSE);
|
||||
$gin_settings->set('icon_path', drupal_get_path('module', 'farm_ui_theme') . '/logo.png');
|
||||
$path = \Drupal::service('extension.list.module')->getPath('farm_ui_theme');
|
||||
$gin_settings->set('logo.use_default', FALSE);
|
||||
$gin_settings->set('logo.path', $path . '/logo.png');
|
||||
$gin_settings->set('favicon.use_default', FALSE);
|
||||
$gin_settings->set('favicon.path', drupal_get_path('module', 'farm_ui_theme') . '/favicon.ico');
|
||||
$gin_settings->set('favicon.path', $path . '/favicon.ico');
|
||||
|
||||
// Save Gin settings.
|
||||
$gin_settings->save();
|
||||
|
@ -81,3 +82,15 @@ function farm_ui_theme_uninstall() {
|
|||
$local_actions_block->set('settings.provider', 'core');
|
||||
$local_actions_block->save();
|
||||
}
|
||||
|
||||
/**
|
||||
* Update Gin theme logo settings.
|
||||
*/
|
||||
function farm_ui_theme_update_9000(&$sandbox) {
|
||||
$gin_settings = \Drupal::configFactory()->getEditable('gin.settings');
|
||||
$gin_settings->set('logo.use_default', $gin_settings->get('icon_default'));
|
||||
$gin_settings->clear('icon_default');
|
||||
$gin_settings->set('logo.path', $gin_settings->get('icon_path'));
|
||||
$gin_settings->clear('icon_path');
|
||||
$gin_settings->save();
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@ dependencies:
|
|||
- csv_serialization
|
||||
- entity_browser
|
||||
- farm_location
|
||||
- farm_ui_views
|
||||
- image
|
||||
- options
|
||||
- rest
|
||||
|
@ -1715,23 +1716,6 @@ display:
|
|||
- url.query_args
|
||||
- user.permissions
|
||||
tags: { }
|
||||
page_1:
|
||||
id: page_1
|
||||
display_title: 'Assigned (page)'
|
||||
display_plugin: page
|
||||
position: 7
|
||||
display_options:
|
||||
arguments:
|
||||
owner_target_id:
|
||||
id: owner_target_id
|
||||
table: asset__owner
|
||||
field: owner_target_id
|
||||
relationship: none
|
||||
group_type: group
|
||||
admin_label: ''
|
||||
entity_type: asset
|
||||
entity_field: owner
|
||||
plugin_id: numeric
|
||||
default_action: 'not found'
|
||||
exception:
|
||||
value: all
|
||||
|
@ -1746,38 +1730,117 @@ display:
|
|||
summary_options:
|
||||
base_path: ''
|
||||
count: true
|
||||
override: false
|
||||
items_per_page: 25
|
||||
summary:
|
||||
sort_order: asc
|
||||
number_of_records: 0
|
||||
format: default_summary
|
||||
specify_validation: true
|
||||
validate:
|
||||
type: 'entity:user'
|
||||
cache_metadata:
|
||||
max-age: 0
|
||||
contexts:
|
||||
- 'languages:language_content'
|
||||
- 'languages:language_interface'
|
||||
- url
|
||||
- url.query_args
|
||||
- user.permissions
|
||||
tags: { }
|
||||
page_term:
|
||||
display_plugin: page
|
||||
id: page_term
|
||||
display_title: 'By term (page)'
|
||||
position: 4
|
||||
display_options:
|
||||
display_extenders: { }
|
||||
display_description: ''
|
||||
path: taxonomy/term/%taxonomy_term/assets/%entity_bundle
|
||||
arguments:
|
||||
asset_taxonomy_term_reference:
|
||||
id: asset_taxonomy_term_reference
|
||||
table: asset_field_data
|
||||
field: asset_taxonomy_term_reference
|
||||
relationship: none
|
||||
group_type: group
|
||||
admin_label: ''
|
||||
break_phrase: false
|
||||
default_action: 'not found'
|
||||
exception:
|
||||
value: all
|
||||
title_enable: false
|
||||
title: All
|
||||
title_enable: false
|
||||
title: ''
|
||||
default_argument_type: fixed
|
||||
default_argument_options:
|
||||
argument: ''
|
||||
default_argument_skip_url: false
|
||||
summary_options:
|
||||
base_path: ''
|
||||
count: true
|
||||
items_per_page: 25
|
||||
override: false
|
||||
summary:
|
||||
sort_order: asc
|
||||
number_of_records: 0
|
||||
format: default_summary
|
||||
specify_validation: true
|
||||
validate:
|
||||
type: 'entity:taxonomy_term'
|
||||
fail: 'not found'
|
||||
validate_options:
|
||||
operation: view
|
||||
access: false
|
||||
multiple: 0
|
||||
bundles: {}
|
||||
entity_type: asset
|
||||
plugin_id: entity_taxonomy_term_reference
|
||||
type:
|
||||
id: type
|
||||
table: asset_field_data
|
||||
field: type
|
||||
relationship: none
|
||||
group_type: group
|
||||
admin_label: ''
|
||||
default_action: 'not found'
|
||||
exception:
|
||||
value: all
|
||||
title_enable: false
|
||||
title: All
|
||||
title_enable: false
|
||||
title: ''
|
||||
default_argument_type: fixed
|
||||
default_argument_options:
|
||||
argument: all
|
||||
default_argument_skip_url: false
|
||||
summary_options:
|
||||
base_path: ''
|
||||
count: true
|
||||
items_per_page: 25
|
||||
override: false
|
||||
summary:
|
||||
sort_order: asc
|
||||
number_of_records: 0
|
||||
format: default_summary
|
||||
specify_validation: true
|
||||
validate:
|
||||
type: 'entity:asset_type'
|
||||
fail: 'not found'
|
||||
validate_options:
|
||||
operation: view
|
||||
multiple: 0
|
||||
restrict_roles: false
|
||||
roles: { }
|
||||
access: false
|
||||
bundles: { }
|
||||
glossary: false
|
||||
limit: 0
|
||||
case: none
|
||||
path_case: none
|
||||
transform_dash: false
|
||||
break_phrase: false
|
||||
not: false
|
||||
entity_type: asset
|
||||
entity_field: type
|
||||
plugin_id: string
|
||||
defaults:
|
||||
arguments: false
|
||||
display_description: ''
|
||||
display_extenders: { }
|
||||
path: user/%user/assets
|
||||
menu:
|
||||
type: tab
|
||||
title: Assets
|
||||
description: ''
|
||||
weight: 0
|
||||
expanded: false
|
||||
menu_name: account
|
||||
parent: ''
|
||||
context: '0'
|
||||
cache_metadata:
|
||||
max-age: 0
|
||||
contexts:
|
||||
|
|
|
@ -2471,7 +2471,7 @@ display:
|
|||
entity_type: log
|
||||
entity_field: type
|
||||
plugin_id: string
|
||||
default_action: ignore
|
||||
default_action: 'not found'
|
||||
exception:
|
||||
value: all
|
||||
title_enable: false
|
||||
|
@ -2521,6 +2521,112 @@ display:
|
|||
- user
|
||||
- user.permissions
|
||||
tags: { }
|
||||
page_term:
|
||||
display_plugin: page
|
||||
id: page_term
|
||||
display_title: 'By term (page)'
|
||||
position: 2
|
||||
display_options:
|
||||
display_extenders: { }
|
||||
display_description: ''
|
||||
path: taxonomy/term/%taxonomy_term/logs/%entity_bundle
|
||||
arguments:
|
||||
log_taxonomy_term_reference:
|
||||
id: log_taxonomy_term_reference
|
||||
table: log_field_data
|
||||
field: log_taxonomy_term_reference
|
||||
relationship: none
|
||||
group_type: group
|
||||
admin_label: ''
|
||||
break_phrase: false
|
||||
default_action: 'not found'
|
||||
exception:
|
||||
value: all
|
||||
title_enable: false
|
||||
title: All
|
||||
title_enable: false
|
||||
title: ''
|
||||
default_argument_type: fixed
|
||||
default_argument_options:
|
||||
argument: ''
|
||||
default_argument_skip_url: false
|
||||
summary_options:
|
||||
base_path: ''
|
||||
count: true
|
||||
items_per_page: 25
|
||||
override: false
|
||||
summary:
|
||||
sort_order: asc
|
||||
number_of_records: 0
|
||||
format: default_summary
|
||||
specify_validation: true
|
||||
validate:
|
||||
type: 'entity:taxonomy_term'
|
||||
fail: 'not found'
|
||||
validate_options:
|
||||
operation: view
|
||||
access: false
|
||||
multiple: 0
|
||||
bundles: {}
|
||||
entity_type: log
|
||||
plugin_id: entity_taxonomy_term_reference
|
||||
type:
|
||||
id: type
|
||||
table: log_field_data
|
||||
field: type
|
||||
relationship: none
|
||||
group_type: group
|
||||
admin_label: ''
|
||||
default_action: 'not found'
|
||||
exception:
|
||||
value: all
|
||||
title_enable: false
|
||||
title: All
|
||||
title_enable: false
|
||||
title: ''
|
||||
default_argument_type: fixed
|
||||
default_argument_options:
|
||||
argument: all
|
||||
default_argument_skip_url: false
|
||||
summary_options:
|
||||
base_path: ''
|
||||
count: true
|
||||
items_per_page: 25
|
||||
override: false
|
||||
summary:
|
||||
sort_order: asc
|
||||
number_of_records: 0
|
||||
format: default_summary
|
||||
specify_validation: true
|
||||
validate:
|
||||
type: 'entity:log_type'
|
||||
fail: 'not found'
|
||||
validate_options:
|
||||
operation: view
|
||||
multiple: 0
|
||||
access: false
|
||||
bundles: { }
|
||||
glossary: false
|
||||
limit: 0
|
||||
case: none
|
||||
path_case: none
|
||||
transform_dash: false
|
||||
break_phrase: false
|
||||
entity_type: log
|
||||
entity_field: type
|
||||
plugin_id: string
|
||||
defaults:
|
||||
arguments: false
|
||||
cache_metadata:
|
||||
max-age: 0
|
||||
contexts:
|
||||
- 'languages:language_content'
|
||||
- 'languages:language_interface'
|
||||
- url
|
||||
- url.query_args
|
||||
- user
|
||||
- user.permissions
|
||||
tags: { }
|
||||
page_type:
|
||||
id: page_type
|
||||
display_title: 'By type (page)'
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
# Add log view tabs to assets.
|
||||
farm.asset.logs:
|
||||
title: 'Logs'
|
||||
route_name: view.farm_log.page_asset
|
||||
|
@ -13,3 +14,21 @@ farm.asset.logs.all:
|
|||
parent_id: farm.asset.logs
|
||||
farm.asset.logs.type:
|
||||
deriver: Drupal\farm_ui_views\Plugin\Derivative\FarmLogViewsTaskLink
|
||||
|
||||
# Add asset/log view tabs to taxonomy terms.
|
||||
farm.taxonomy_term.assets:
|
||||
title: 'Assets'
|
||||
route_name: view.farm_asset.page_term
|
||||
route_parameters:
|
||||
entity_bundle: 'all'
|
||||
base_route: entity.taxonomy_term.canonical
|
||||
weight: 50
|
||||
farm.taxonomy_term.logs:
|
||||
title: 'Logs'
|
||||
route_name: view.farm_log.page_term
|
||||
route_parameters:
|
||||
entity_bundle: 'all'
|
||||
base_route: entity.taxonomy_term.canonical
|
||||
weight: 50
|
||||
farm.taxonomy_term.entities.type:
|
||||
deriver: Drupal\farm_ui_views\Plugin\Derivative\FarmTaxonomyTermViewsTaskLink
|
||||
|
|
|
@ -278,5 +278,8 @@ function farm_ui_views_get_bundle_argument(ViewExecutable $view, string $display
|
|||
elseif ($view->id() == 'farm_log' && $display_id == 'page_asset' && !empty($args[1]) && $args[1] != 'all') {
|
||||
$bundle = $args[1];
|
||||
}
|
||||
elseif (in_array($view->id(), ['farm_asset', 'farm_log']) && $display_id == 'page_term' && !empty($args[1]) && $args[1] != 'all') {
|
||||
$bundle = $args[1];
|
||||
}
|
||||
return $bundle;
|
||||
}
|
||||
|
|
|
@ -13,6 +13,24 @@ services:
|
|||
arguments: [ '@entity_type.manager', '@asset.location' ]
|
||||
tags:
|
||||
- { name: access_check, applies_to: _asset_children_access }
|
||||
farm_ui_views.asset_term_access:
|
||||
class: Drupal\farm_ui_views\Access\FarmTaxonomyTermEntityViewsAccessCheck
|
||||
arguments:
|
||||
- 'asset'
|
||||
- '@entity_type.manager'
|
||||
- '@entity_type.bundle.info'
|
||||
- '@entity_field.manager'
|
||||
tags:
|
||||
- { name: access_check, applies_to: _asset_term_access }
|
||||
farm_ui_views.log_term_access:
|
||||
class: Drupal\farm_ui_views\Access\FarmTaxonomyTermEntityViewsAccessCheck
|
||||
arguments:
|
||||
- 'log'
|
||||
- '@entity_type.manager'
|
||||
- '@entity_type.bundle.info'
|
||||
- '@entity_field.manager'
|
||||
tags:
|
||||
- { name: access_check, applies_to: _log_term_access }
|
||||
farm_ui_views.asset_inventory_access:
|
||||
class: Drupal\farm_ui_views\Access\FarmInventoryAssetViewsAccessCheck
|
||||
arguments: [ '@entity_type.manager' ]
|
||||
|
|
|
@ -20,4 +20,26 @@ function farm_ui_views_views_data_alter(array &$data) {
|
|||
],
|
||||
];
|
||||
}
|
||||
|
||||
// Provide an asset_taxonomy_term_reference argument for views of assets.
|
||||
if (isset($data['asset_field_data'])) {
|
||||
$data['asset_field_data']['asset_taxonomy_term_reference'] = [
|
||||
'title' => t('Asset Taxonomy Term Reference'),
|
||||
'help' => t('Taxonomy Terms that are referenced by the asset.'),
|
||||
'argument' => [
|
||||
'id' => 'entity_taxonomy_term_reference',
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
// Provide a log_taxonomy_term_reference argument for views of logs.
|
||||
if (isset($data['log_field_data'])) {
|
||||
$data['log_field_data']['log_taxonomy_term_reference'] = [
|
||||
'title' => t('Log Taxonomy Term Reference'),
|
||||
'help' => t('Taxonomy Terms that are referenced by the log.'),
|
||||
'argument' => [
|
||||
'id' => 'entity_taxonomy_term_reference',
|
||||
],
|
||||
];
|
||||
}
|
||||
}
|
||||
|
|
|
@ -129,6 +129,41 @@ function farm_ui_views_views_pre_render(ViewExecutable $view) {
|
|||
}
|
||||
}
|
||||
|
||||
// If this is the farm_asset/farm_log View and page_term display, include
|
||||
// the term's name.
|
||||
if (in_array($view->id(), ['farm_asset', 'farm_log']) && $view->current_display == 'page_term') {
|
||||
$term_id = $view->args[0];
|
||||
$entity_bundle = $view->args[1];
|
||||
$term = \Drupal::entityTypeManager()->getStorage('taxonomy_term')->load($term_id);
|
||||
|
||||
if (!empty($term)) {
|
||||
$vocabulary = \Drupal::entityTypeManager()->getStorage('taxonomy_vocabulary')->load($term->bundle());
|
||||
|
||||
$entity_bundle_label = '';
|
||||
if ($entity_bundle != 'all') {
|
||||
$bundles = \Drupal::service('entity_type.bundle.info')->getBundleInfo($view->getBaseEntityType()->id());
|
||||
if (!empty($bundles[$entity_bundle])) {
|
||||
$entity_bundle_label = $bundles[$entity_bundle]['label'] . ' ' . $view->getBaseEntityType()->getPluralLabel();
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($entity_bundle_label)) {
|
||||
$title = t('%bundle with %vocab term %term', [
|
||||
'%bundle' => $entity_bundle_label,
|
||||
'%vocab' => $vocabulary->label(),
|
||||
'%term' => $term->label(),
|
||||
]);
|
||||
}
|
||||
else {
|
||||
$title = t('%base_type with %vocab term %term', [
|
||||
'%base_type' => $view->getBaseEntityType()->getCollectionLabel(),
|
||||
'%vocab' => $vocabulary->label(),
|
||||
'%term' => $term->label(),
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Set the title, if so desired.
|
||||
if (!empty($title)) {
|
||||
$view->setTitle($title);
|
||||
|
|
|
@ -0,0 +1,111 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\farm_ui_views\Access;
|
||||
|
||||
use Drupal\Core\Entity\EntityFieldManagerInterface;
|
||||
use Drupal\Core\Entity\EntityTypeBundleInfoInterface;
|
||||
use Drupal\Core\Entity\EntityTypeManagerInterface;
|
||||
use Drupal\Core\Routing\Access\AccessInterface;
|
||||
use Drupal\Core\Routing\RouteMatchInterface;
|
||||
use Drupal\Core\Access\AccessResult;
|
||||
|
||||
/**
|
||||
* Checks access for displaying Views of entities that reference taxonomy terms.
|
||||
*/
|
||||
class FarmTaxonomyTermEntityViewsAccessCheck implements AccessInterface {
|
||||
|
||||
/**
|
||||
* The base entity type of the views this access check will be applied to.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $baseEntityType;
|
||||
|
||||
/**
|
||||
* The taxonomy term storage.
|
||||
*
|
||||
* @var \Drupal\Core\Entity\EntityStorageInterface
|
||||
*/
|
||||
protected $taxonomyTermStorage;
|
||||
|
||||
/**
|
||||
* The entity type bundle info.
|
||||
*
|
||||
* @var \Drupal\Core\Entity\EntityTypeBundleInfoInterface
|
||||
*/
|
||||
protected $entityTypeBundleInfo;
|
||||
|
||||
/**
|
||||
* The entity field manager service.
|
||||
*
|
||||
* @var \Drupal\Core\Entity\EntityFieldManagerInterface
|
||||
*/
|
||||
protected $entityFieldManager;
|
||||
|
||||
/**
|
||||
* FarmTaxonomyTermEntityViewsAccessCheck constructor.
|
||||
*
|
||||
* @param string $base_entity_type
|
||||
* The base entity type of the views this access check will be applied to.
|
||||
* @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
|
||||
* The entity type manager service.
|
||||
* @param \Drupal\Core\Entity\EntityTypeBundleInfoInterface $entity_bundle_info
|
||||
* The entity type bundle info service.
|
||||
* @param \Drupal\Core\Entity\EntityFieldManagerInterface $entity_field_manager
|
||||
* The entity field manager service.
|
||||
*/
|
||||
public function __construct($base_entity_type,
|
||||
EntityTypeManagerInterface $entity_type_manager,
|
||||
EntityTypeBundleInfoInterface $entity_bundle_info,
|
||||
EntityFieldManagerInterface $entity_field_manager) {
|
||||
$this->baseEntityType = $base_entity_type;
|
||||
$this->taxonomyTermStorage = $entity_type_manager->getStorage('taxonomy_term');
|
||||
$this->entityTypeBundleInfo = $entity_bundle_info;
|
||||
$this->entityFieldManager = $entity_field_manager;
|
||||
}
|
||||
|
||||
/**
|
||||
* A custom access check to filter out irrelevant entity bundles.
|
||||
*
|
||||
* @param \Drupal\Core\Routing\RouteMatchInterface $route_match
|
||||
* The route match.
|
||||
*/
|
||||
public function access(RouteMatchInterface $route_match) {
|
||||
|
||||
// If there is no "taxonomy_term" or "asset_type" parameter, bail.
|
||||
$term_id = $route_match->getParameter('taxonomy_term');
|
||||
$entity_bundle = $route_match->getParameter('entity_bundle');
|
||||
|
||||
if (empty($term_id) || empty($entity_bundle)) {
|
||||
return AccessResult::forbidden();
|
||||
}
|
||||
|
||||
$term = $this->taxonomyTermStorage->load($term_id);
|
||||
|
||||
// Loop through all the entity bundles of the base entity type for the view
|
||||
// and only return AccessResult::allowed() for those which have a taxonomy
|
||||
// term entity reference field referencing the taxonomy term bundle of the
|
||||
// term we loaded above.
|
||||
$bundles = $this->entityTypeBundleInfo->getBundleInfo($this->baseEntityType);
|
||||
foreach (array_keys($bundles) as $type) {
|
||||
// If the route argument is 'all' then we check all the bundles, otherwise
|
||||
// only check the one that matches.
|
||||
if ($entity_bundle == 'all' || $type == $entity_bundle) {
|
||||
$field_definitions = $this->entityFieldManager->getFieldDefinitions($this->baseEntityType, $type);
|
||||
|
||||
foreach (array_values($field_definitions) as $field_definition) {
|
||||
if ($field_definition->getType() == "entity_reference" && $field_definition->getSetting('target_type') == "taxonomy_term") {
|
||||
$handler_settings = $field_definition->getSetting('handler_settings') ?? [];
|
||||
|
||||
if (in_array($term->bundle(), $handler_settings['target_bundles'] ?? [])) {
|
||||
return AccessResult::allowed();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return AccessResult::forbidden();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,82 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\farm_ui_views\Plugin\Derivative;
|
||||
|
||||
use Drupal\Component\Plugin\Derivative\DeriverBase;
|
||||
use Drupal\Core\Entity\EntityTypeBundleInfoInterface;
|
||||
use Drupal\Core\Plugin\Discovery\ContainerDeriverInterface;
|
||||
use Drupal\Core\StringTranslation\StringTranslationTrait;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
|
||||
/**
|
||||
* Provides task links for farmOS Taxonomy Term Views.
|
||||
*/
|
||||
class FarmTaxonomyTermViewsTaskLink extends DeriverBase implements ContainerDeriverInterface {
|
||||
|
||||
use StringTranslationTrait;
|
||||
|
||||
/**
|
||||
* The entity type bundle info.
|
||||
*
|
||||
* @var \Drupal\Core\Entity\EntityTypeBundleInfoInterface
|
||||
*/
|
||||
protected $entityTypeBundleInfo;
|
||||
|
||||
/**
|
||||
* Constructs a FarmTaxonomyTermViewsTaskLink instance.
|
||||
*
|
||||
* @param \Drupal\Core\Entity\EntityTypeBundleInfoInterface $entity_bundle_info
|
||||
* The entity type bundle info service.
|
||||
*/
|
||||
public function __construct(EntityTypeBundleInfoInterface $entity_bundle_info) {
|
||||
$this->entityTypeBundleInfo = $entity_bundle_info;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function create(ContainerInterface $container, $base_plugin_id) {
|
||||
return new static(
|
||||
$container->get('entity_type.bundle.info')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getDerivativeDefinitions($base_plugin_definition) {
|
||||
$links = [];
|
||||
|
||||
foreach (['asset', 'log'] as $entity_type) {
|
||||
|
||||
$links["farm.taxonomy_term.{$entity_type}s.all"] = [
|
||||
'id' => "farm.taxonomy_term.{$entity_type}s.all",
|
||||
'title' => 'All',
|
||||
'parent_id' => "farm.taxonomy_term.{$entity_type}s",
|
||||
'route_name' => "view.farm_$entity_type.page_term",
|
||||
'route_parameters' => [
|
||||
'entity_bundle' => 'all',
|
||||
],
|
||||
] + $base_plugin_definition;
|
||||
|
||||
// Add links for each entity bundle.
|
||||
$entity_bundles = $this->entityTypeBundleInfo->getBundleInfo($entity_type);
|
||||
foreach ($entity_bundles as $entity_bundle => $info) {
|
||||
|
||||
$links["farm.taxonomy_term.{$entity_type}s.$entity_bundle"] = [
|
||||
'id' => "farm.taxonomy_term.{$entity_type}s.$entity_bundle",
|
||||
'title' => $info['label'],
|
||||
'parent_id' => "farm.taxonomy_term.{$entity_type}s",
|
||||
'route_name' => "view.farm_$entity_type.page_term",
|
||||
'route_parameters' => [
|
||||
'entity_bundle' => $entity_bundle,
|
||||
],
|
||||
] + $base_plugin_definition;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return $links;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,194 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\farm_ui_views\Plugin\views\argument;
|
||||
|
||||
use Drupal\Core\Entity\Sql\SqlContentEntityStorage;
|
||||
use Drupal\Core\Entity\EntityFieldManagerInterface;
|
||||
use Drupal\Core\Entity\EntityStorageInterface;
|
||||
use Drupal\Core\Entity\EntityTypeBundleInfoInterface;
|
||||
use Drupal\Core\Entity\EntityTypeManagerInterface;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
use Drupal\taxonomy\Plugin\views\argument\Taxonomy;
|
||||
use Drupal\views\Views;
|
||||
|
||||
/**
|
||||
* Argument handler for taxonomy term references from an arbitrary entity field.
|
||||
*
|
||||
* @ingroup views_argument_handlers
|
||||
*
|
||||
* @ViewsArgument("entity_taxonomy_term_reference")
|
||||
*/
|
||||
class EntityTaxonomyTermReferenceArgument extends Taxonomy {
|
||||
|
||||
/**
|
||||
* The entity type manager service.
|
||||
*
|
||||
* @var \Drupal\Core\Entity\EntityTypeManagerInterface
|
||||
*/
|
||||
protected $entityTypeManager;
|
||||
|
||||
/**
|
||||
* The entity type bundle info.
|
||||
*
|
||||
* @var \Drupal\Core\Entity\EntityTypeBundleInfoInterface
|
||||
*/
|
||||
protected $entityTypeBundleInfo;
|
||||
|
||||
/**
|
||||
* The entity field manager service.
|
||||
*
|
||||
* @var \Drupal\Core\Entity\EntityFieldManagerInterface
|
||||
*/
|
||||
protected $entityFieldManager;
|
||||
|
||||
/**
|
||||
* EntityTaxonomyTermReferenceArgument constructor.
|
||||
*
|
||||
* @param array $configuration
|
||||
* A configuration array containing information about the plugin instance.
|
||||
* @param string $plugin_id
|
||||
* The plugin ID for the plugin instance.
|
||||
* @param mixed $plugin_definition
|
||||
* The plugin implementation definition.
|
||||
* @param \Drupal\Core\Entity\EntityStorageInterface $term_storage
|
||||
* The taxonomy term storage service.
|
||||
* @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
|
||||
* The entity type manager service.
|
||||
* @param \Drupal\Core\Entity\EntityTypeBundleInfoInterface $entity_bundle_info
|
||||
* The entity type bundle info service.
|
||||
* @param \Drupal\Core\Entity\EntityFieldManagerInterface $entity_field_manager
|
||||
* The entity field manager service.
|
||||
*/
|
||||
public function __construct(array $configuration,
|
||||
$plugin_id,
|
||||
$plugin_definition,
|
||||
EntityStorageInterface $term_storage,
|
||||
EntityTypeManagerInterface $entity_type_manager,
|
||||
EntityTypeBundleInfoInterface $entity_bundle_info,
|
||||
EntityFieldManagerInterface $entity_field_manager) {
|
||||
parent::__construct($configuration, $plugin_id, $plugin_definition, $term_storage);
|
||||
$this->entityTypeManager = $entity_type_manager;
|
||||
$this->entityTypeBundleInfo = $entity_bundle_info;
|
||||
$this->entityFieldManager = $entity_field_manager;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
|
||||
return new static($configuration, $plugin_id, $plugin_definition,
|
||||
$container->get('entity_type.manager')->getStorage('taxonomy_term'),
|
||||
$container->get('entity_type.manager'),
|
||||
$container->get('entity_type.bundle.info'),
|
||||
$container->get('entity_field.manager'));
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function query($group_by = FALSE) {
|
||||
// Getting the arguments through views rather than
|
||||
// from the Drupal route is important since it allows
|
||||
// the contextual filter previews in the views UI to
|
||||
// work correctly.
|
||||
$term_id = $this->argument;
|
||||
$entity_bundle = $this->view->args[1] ?: 'all';
|
||||
|
||||
if (empty($term_id)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$term = $this->termStorage->load($term_id);
|
||||
|
||||
// This is a value like 'asset' or 'log'.
|
||||
$base_entity_type = $this->view->getBaseEntityType()->id();
|
||||
|
||||
$entity_storage = $this->entityTypeManager->getStorage($base_entity_type);
|
||||
|
||||
if (!($entity_storage instanceof SqlContentEntityStorage)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$entity_data_table = $entity_storage->getDataTable();
|
||||
|
||||
$entity_table_mapping = $entity_storage->getTableMapping();
|
||||
|
||||
$conditions = [];
|
||||
|
||||
// Keep track of which field tables we've already joined with since some
|
||||
// assets share the same field e.g. plant and seed assets.
|
||||
$already_joined_term_field_tables = [];
|
||||
|
||||
// Loop through all the bundles of the base entity type for this view.
|
||||
$bundles = $this->entityTypeBundleInfo->getBundleInfo($base_entity_type);
|
||||
foreach (array_keys($bundles) as $type) {
|
||||
// Consider either all of them or just the one matching the
|
||||
// bundle argument.
|
||||
if ($entity_bundle == 'all' || $type == $entity_bundle) {
|
||||
$field_definitions = $this->entityFieldManager->getFieldDefinitions($base_entity_type, $type);
|
||||
|
||||
foreach ($field_definitions as $field_id => $field_definition) {
|
||||
// Look for taxonomy term entity reference fields which reference the
|
||||
// target bundle of the term we loaded above.
|
||||
if ($field_definition->getType() == "entity_reference" && $field_definition->getSetting('target_type') == "taxonomy_term") {
|
||||
$handler_settings = $field_definition->getSetting('handler_settings') ?? [];
|
||||
|
||||
if (in_array($term->bundle(), $handler_settings['target_bundles'] ?? [])) {
|
||||
|
||||
// Now that we have found such a field, get the parameters to
|
||||
// construct a join to allow us to filter only those entities
|
||||
// which actually reference the term we loaded above.
|
||||
$field_table_name = $entity_table_mapping->getFieldTableName($field_id);
|
||||
|
||||
// Don't add the same join more than once.
|
||||
if (array_key_exists($field_table_name, $already_joined_term_field_tables)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$column_names = $entity_table_mapping->getColumnNames($field_id);
|
||||
|
||||
$target_id_column_name = $column_names['target_id'];
|
||||
|
||||
// Join the taxonomy reference field table with the entity.
|
||||
/** @var \Drupal\views\Plugin\views\join\JoinPluginBase $join */
|
||||
$join = Views::pluginManager('join')->createInstance('standard', [
|
||||
'table' => $field_table_name,
|
||||
'field' => 'entity_id',
|
||||
'left_table' => $entity_data_table,
|
||||
'left_field' => 'id',
|
||||
'extra' => [
|
||||
[
|
||||
'field' => 'deleted',
|
||||
'value' => 0,
|
||||
],
|
||||
[
|
||||
'field' => $target_id_column_name,
|
||||
'value' => $term->id(),
|
||||
],
|
||||
],
|
||||
]);
|
||||
|
||||
// Add the relationship.
|
||||
$relationship_alias = $this->query->addRelationship($field_table_name, $join, $entity_data_table);
|
||||
|
||||
// Keep track that we've now joined with that field table.
|
||||
$already_joined_term_field_tables[$field_table_name] = 1;
|
||||
|
||||
// Add a condition to our final WHERE statement that the joined
|
||||
// taxonomy term reference target id is not NULL.
|
||||
$conditions[] = "$relationship_alias.$target_id_column_name IS NOT NULL";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($conditions)) {
|
||||
$combined_conditions = implode(" OR ", $conditions);
|
||||
|
||||
$this->query->addWhereExpression(0, "$entity_data_table.id IS NOT NULL AND ($combined_conditions)");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -28,6 +28,18 @@ class RouteSubscriber extends RouteSubscriberBase {
|
|||
$route->setRequirement('_asset_children_access', 'Drupal\farm_ui_views\Access\FarmAssetChildrenViewsAccessCheck::access');
|
||||
}
|
||||
|
||||
// Add our _asset_term_access requirement to
|
||||
// view.farm_asset.page_term.
|
||||
if ($route = $collection->get('view.farm_asset.page_term')) {
|
||||
$route->setRequirement('_asset_term_access', 'Drupal\farm_ui_views\Access\FarmTaxonomyTermEntityViewsAccessCheck::access');
|
||||
}
|
||||
|
||||
// Add our _log_term_access requirement to
|
||||
// view.farm_log.page_term.
|
||||
if ($route = $collection->get('view.farm_log.page_term')) {
|
||||
$route->setRequirement('_log_term_access', 'Drupal\farm_ui_views\Access\FarmTaxonomyTermEntityViewsAccessCheck::access');
|
||||
}
|
||||
|
||||
// Add our _location_assets_access requirement to
|
||||
// view.farm_asset.page_location.
|
||||
if ($route = $collection->get('view.farm_asset.page_location')) {
|
||||
|
|
|
@ -0,0 +1,166 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\farm_ui_views\Functional;
|
||||
|
||||
use Drupal\asset\Entity\Asset;
|
||||
use Drupal\Tests\farm_test\Functional\FarmBrowserTestBase;
|
||||
|
||||
/**
|
||||
* Tests the farm_ui_views taxonomy views routes.
|
||||
*
|
||||
* @group farm
|
||||
*/
|
||||
class TaxonomyTermTasksTest extends FarmBrowserTestBase {
|
||||
|
||||
/**
|
||||
* Test user.
|
||||
*
|
||||
* @var \Drupal\user\Entity\User
|
||||
*/
|
||||
protected $user;
|
||||
|
||||
/**
|
||||
* Test animal asset.
|
||||
*
|
||||
* @var \Drupal\asset\Entity\Asset
|
||||
*/
|
||||
protected $favaPlantType;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $defaultTheme = 'classy';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $modules = [
|
||||
'block',
|
||||
'farm_plant',
|
||||
'farm_seed',
|
||||
'farm_ui_views',
|
||||
];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp(): void {
|
||||
parent::setUp();
|
||||
|
||||
$this->drupalPlaceBlock('local_tasks_block');
|
||||
|
||||
// Create/login a user with permission to access taxonomy pages and assets.
|
||||
$this->user = $this->createUser(['administer taxonomy', 'view any asset']);
|
||||
$this->drupalLogin($this->user);
|
||||
|
||||
$entity_type_manager = $this->container->get('entity_type.manager');
|
||||
$term_storage = $entity_type_manager->getStorage('taxonomy_term');
|
||||
|
||||
// Create a "Oat" plant type term.
|
||||
$oat_plant_type = $term_storage->create([
|
||||
'name' => 'Oat',
|
||||
'vid' => 'plant_type',
|
||||
]);
|
||||
$oat_plant_type->save();
|
||||
|
||||
// Create a oat plant.
|
||||
Asset::create([
|
||||
'name' => 'Pringle\'s Progress Oat Planting',
|
||||
'type' => 'plant',
|
||||
'plant_type' => ['target_id' => $oat_plant_type->id()],
|
||||
])->save();
|
||||
|
||||
// Create a "Fava Bean" plant type term.
|
||||
$this->favaPlantType = $term_storage->create([
|
||||
'name' => 'Fava Bean',
|
||||
'vid' => 'plant_type',
|
||||
]);
|
||||
$this->favaPlantType->save();
|
||||
|
||||
// Create a fava plant.
|
||||
Asset::create([
|
||||
'name' => 'Red Flowering Fava Planting',
|
||||
'type' => 'plant',
|
||||
'plant_type' => ['target_id' => $this->favaPlantType->id()],
|
||||
])->save();
|
||||
|
||||
// Create a fava seed.
|
||||
Asset::create([
|
||||
'name' => 'Red Flowering Fava Seeds',
|
||||
'type' => 'seed',
|
||||
'plant_type' => ['target_id' => $this->favaPlantType->id()],
|
||||
])->save();
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that the asset view task links appear on taxonomy term pages.
|
||||
*/
|
||||
public function testTaxonomyTermAssetTaskTabsAppear() {
|
||||
$fava_term_url = 'taxonomy/term/' . $this->favaPlantType->id();
|
||||
|
||||
$this->drupalGet($fava_term_url);
|
||||
$this->assertSession()->statusCodeEquals(200);
|
||||
|
||||
$get_array_of_link_text_by_url = function ($elems) {
|
||||
$result = [];
|
||||
foreach ($elems as $elem) {
|
||||
$result[$elem->getAttribute('href')] = $elem->getText();
|
||||
}
|
||||
return $result;
|
||||
};
|
||||
|
||||
$primary_tab_links = $get_array_of_link_text_by_url($this->xpath('//*[contains(@class, :class)]//a', [
|
||||
':class' => 'tabs primary',
|
||||
]));
|
||||
|
||||
$assert_has_link = function ($elements, $url, $label) {
|
||||
$this->assertArrayHasKey($url, $elements, "No link exists with url '$url' among: " . print_r($elements, TRUE));
|
||||
|
||||
$this->assertEquals($label, $elements[$url], "Link label not as expected.");
|
||||
};
|
||||
|
||||
$assert_has_link($primary_tab_links, "/$fava_term_url/assets/all", 'Assets');
|
||||
|
||||
$this->drupalGet("$fava_term_url/assets/all");
|
||||
$this->assertSession()->statusCodeEquals(200);
|
||||
|
||||
$secondary_tab_links = $get_array_of_link_text_by_url($this->xpath('//*[contains(@class, :class)]//a', [
|
||||
':class' => 'tabs secondary',
|
||||
]));
|
||||
|
||||
$this->assertCount(3, $secondary_tab_links, 'Only 3 secondary tabs appear.');
|
||||
|
||||
$assert_has_link($secondary_tab_links, "/$fava_term_url/assets/all", 'All(active tab)');
|
||||
$assert_has_link($secondary_tab_links, "/$fava_term_url/assets/plant", 'Plant');
|
||||
$assert_has_link($secondary_tab_links, "/$fava_term_url/assets/seed", 'Seed');
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that the views of assets for terms show the correct assets.
|
||||
*/
|
||||
public function testTaxonomyTermAssetViews() {
|
||||
$fava_term_url = 'taxonomy/term/' . $this->favaPlantType->id();
|
||||
|
||||
$this->drupalGet("$fava_term_url/assets/all");
|
||||
$this->assertSession()->statusCodeEquals(200);
|
||||
|
||||
$this->assertSession()->pageTextContains('Red Flowering Fava Planting');
|
||||
$this->assertSession()->pageTextContains('Red Flowering Fava Seeds');
|
||||
$this->assertSession()->pageTextNotContains('Pringle\'s Progress Oat Planting');
|
||||
|
||||
$this->drupalGet("$fava_term_url/assets/plant");
|
||||
$this->assertSession()->statusCodeEquals(200);
|
||||
|
||||
$this->assertSession()->pageTextContains('Red Flowering Fava Planting');
|
||||
$this->assertSession()->pageTextNotContains('Red Flowering Fava Seeds');
|
||||
$this->assertSession()->pageTextNotContains('Pringle\'s Progress Oat Planting');
|
||||
|
||||
$this->drupalGet("$fava_term_url/assets/seed");
|
||||
$this->assertSession()->statusCodeEquals(200);
|
||||
|
||||
$this->assertSession()->pageTextNotContains('Red Flowering Fava Planting');
|
||||
$this->assertSession()->pageTextContains('Red Flowering Fava Seeds');
|
||||
$this->assertSession()->pageTextNotContains('Pringle\'s Progress Oat Planting');
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue