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]
|
## [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
|
### Fixed
|
||||||
|
|
||||||
- [Only require a name to build map popups #515](https://github.com/farmOS/farmOS/pull/515)
|
- [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,
|
Drupal 7, which required a complete refactor of the codebase. By comparison,
|
||||||
updating from Drupal 9 to 10 will simply involve updating deprecated code.
|
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-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-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
|
[2.0.0-beta1]: https://github.com/farmOS/farmOS/releases/tag/2.0.0-beta1
|
||||||
|
|
|
@ -18,7 +18,7 @@
|
||||||
"require": {
|
"require": {
|
||||||
"cweagans/composer-patches": "^1.6",
|
"cweagans/composer-patches": "^1.6",
|
||||||
"drupal/admin_toolbar": "^2.4",
|
"drupal/admin_toolbar": "^2.4",
|
||||||
"drupal/core": "9.3.9",
|
"drupal/core": "9.3.12",
|
||||||
"drupal/config_update": "^1.7",
|
"drupal/config_update": "^1.7",
|
||||||
"drupal/csv_serialization": "^2.0",
|
"drupal/csv_serialization": "^2.0",
|
||||||
"drupal/date_popup": "^1.1",
|
"drupal/date_popup": "^1.1",
|
||||||
|
@ -30,7 +30,7 @@
|
||||||
"drupal/exif_orientation": "^1.1",
|
"drupal/exif_orientation": "^1.1",
|
||||||
"drupal/fraction": "^2.0",
|
"drupal/fraction": "^2.0",
|
||||||
"drupal/geofield": "^1.33",
|
"drupal/geofield": "^1.33",
|
||||||
"drupal/gin": "3.0-alpha37",
|
"drupal/gin": "^3.0@beta",
|
||||||
"drupal/inline_entity_form": "^1.0@RC",
|
"drupal/inline_entity_form": "^1.0@RC",
|
||||||
"drupal/inspire_tree": "^1.0",
|
"drupal/inspire_tree": "^1.0",
|
||||||
"drupal/jsonapi_extras": "^3.15",
|
"drupal/jsonapi_extras": "^3.15",
|
||||||
|
@ -60,9 +60,6 @@
|
||||||
"drupal/entity": {
|
"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"
|
"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": {
|
"drupal/jsonapi_schema": {
|
||||||
"Issue #3256795: Float fields have a null schema": "https://www.drupal.org/files/issues/2022-01-03/3256795-4.patch",
|
"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"
|
"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",
|
"type": "package",
|
||||||
"package": {
|
"package": {
|
||||||
"name": "farmos/farmos-map",
|
"name": "farmos/farmos-map",
|
||||||
"version": "2.0.3",
|
"version": "2.0.4",
|
||||||
"type": "drupal-library",
|
"type": "drupal-library",
|
||||||
"dist": {
|
"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"
|
"type": "zip"
|
||||||
},
|
},
|
||||||
"extra": {
|
"extra": {
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
{
|
{
|
||||||
"require": {
|
"require": {
|
||||||
"cweagans/composer-patches": "^1.7",
|
"cweagans/composer-patches": "^1.7",
|
||||||
"drupal/core-composer-scaffold": "9.3.9"
|
"drupal/core-composer-scaffold": "9.3.12"
|
||||||
},
|
},
|
||||||
"require-dev": {
|
"require-dev": {
|
||||||
"brianium/paratest": "^4",
|
"brianium/paratest": "^4",
|
||||||
"drupal/core-dev": "9.3.9",
|
"drupal/core-dev": "9.3.12",
|
||||||
"phpspec/prophecy-phpunit": "^2",
|
"phpspec/prophecy-phpunit": "^2",
|
||||||
"symfony/finder": "^4.0"
|
"symfony/finder": "^4.0"
|
||||||
},
|
},
|
||||||
|
|
|
@ -28,4 +28,7 @@ services:
|
||||||
|
|
||||||
# Enable this service when executing javascript tests.
|
# Enable this service when executing javascript tests.
|
||||||
# chrome:
|
# 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'
|
XDEBUG_MODE: 'off'
|
||||||
|
|
||||||
chrome:
|
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
|
```yml
|
||||||
chrome:
|
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
|
## 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
|
types), then they should be added as "base fields" via
|
||||||
`hook_entity_base_field_info()`.
|
`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
|
||||||
<?php
|
<?php
|
||||||
|
@ -24,12 +27,14 @@ use Drupal\Core\Entity\EntityTypeInterface;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Implements hook_entity_base_field_info().
|
* Implements hook_entity_base_field_info().
|
||||||
|
* NOTE: Replace 'mymodule' with the module name.
|
||||||
*/
|
*/
|
||||||
function mymodule_entity_base_field_info(EntityTypeInterface $entity_type) {
|
function mymodule_entity_base_field_info(EntityTypeInterface $entity_type) {
|
||||||
$fields = [];
|
$fields = [];
|
||||||
|
|
||||||
// Add a new string field to Log entities.
|
// 'log' specifies the entity type to apply to.
|
||||||
if ($entity_type->id() == 'log') {
|
if ($entity_type->id() == 'log') {
|
||||||
|
// Options for the new field. See Field options below.
|
||||||
$options = [
|
$options = [
|
||||||
'type' => 'string',
|
'type' => 'string',
|
||||||
'label' => t('My new field'),
|
'label' => t('My new field'),
|
||||||
|
@ -39,6 +44,7 @@ function mymodule_entity_base_field_info(EntityTypeInterface $entity_type) {
|
||||||
'view' => 10,
|
'view' => 10,
|
||||||
],
|
],
|
||||||
];
|
];
|
||||||
|
// NOTE: Replace 'myfield' with the internal name of the field.
|
||||||
$fields['myfield'] = \Drupal::service('farm_field.factory')->baseFieldDefinition($options);
|
$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:
|
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)
|
[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
|
The format for bundle field definitions is identical to base field definitions
|
||||||
(above), but the `bundleFieldDefinition()` method must be used instead of
|
(above), but the `bundleFieldDefinition()` method must be used instead of
|
||||||
`baseFieldDefinition()`.
|
`baseFieldDefinition()`.
|
||||||
|
|
||||||
|
To get started, place the following in the `[modulename].module` file:
|
||||||
|
|
||||||
```php
|
```php
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
@ -67,12 +78,15 @@ use Drupal\Core\Entity\EntityTypeInterface;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Implements hook_farm_entity_bundle_field_info().
|
* 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) {
|
function mymodule_farm_entity_bundle_field_info(EntityTypeInterface $entity_type, $bundle) {
|
||||||
$fields = [];
|
$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') {
|
if ($entity_type->id() == 'log' && $bundle == 'input') {
|
||||||
|
// Options for the new field. See Field options below.
|
||||||
$options = [
|
$options = [
|
||||||
'type' => 'string',
|
'type' => 'string',
|
||||||
'label' => t('My new field'),
|
'label' => t('My new field'),
|
||||||
|
@ -82,6 +96,7 @@ function mymodule_farm_entity_bundle_field_info(EntityTypeInterface $entity_type
|
||||||
'view' => 10,
|
'view' => 10,
|
||||||
],
|
],
|
||||||
];
|
];
|
||||||
|
// NOTE: Replace 'myfield' with the internal name of the field.
|
||||||
$fields['myfield'] = \Drupal::service('farm_field.factory')->bundleFieldDefinition($options);
|
$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
|
in the active configuration of the site. (**Warning** changing core types runs
|
||||||
the risk of conflicting with future farmOS updates).
|
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:
|
### Examples:
|
||||||
|
|
||||||
#### Flag
|
#### Flag
|
||||||
|
@ -140,11 +159,13 @@ dependencies:
|
||||||
enforced:
|
enforced:
|
||||||
module:
|
module:
|
||||||
- my_module
|
- my_module
|
||||||
id: monitor
|
id: organic
|
||||||
label: Monitor
|
label: Organic
|
||||||
entity_types: null
|
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 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
|
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
|
shown in the select field and other parts of the UI, and `entity_types`, which
|
||||||
|
@ -194,6 +215,8 @@ id: field
|
||||||
label: Field
|
label: Field
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Note that the file name is in the form `farm_land.land_type.[id].yml`.
|
||||||
|
|
||||||
#### Structure type
|
#### Structure type
|
||||||
|
|
||||||
The "Structure" module in farmOS provides a "Building" type like this:
|
The "Structure" module in farmOS provides a "Building" type like this:
|
||||||
|
@ -211,6 +234,8 @@ id: building
|
||||||
label: Building
|
label: Building
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Note that the file name is in the form `farm_structure.structure_type.[id].yml`.
|
||||||
|
|
||||||
#### Lab test type
|
#### Lab test type
|
||||||
|
|
||||||
The "Lab test" module in farmOS provides a "Soil test" type like this:
|
The "Lab test" module in farmOS provides a "Soil test" type like this:
|
||||||
|
@ -228,6 +253,8 @@ id: soil
|
||||||
label: Soil test
|
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 type
|
||||||
|
|
||||||
ID tag types are similar to Flags, in that they have an `id` and `label`. They
|
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
|
For example, an "Ear tag" type, provided by the "Animal asset" module, only
|
||||||
applies to "Animal" assets:
|
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
|
```yaml
|
||||||
langcode: en
|
langcode: en
|
||||||
|
@ -253,5 +280,7 @@ bundles:
|
||||||
- animal
|
- 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`.
|
If you want the tag type to apply to all assets, set `bundles: null`.
|
||||||
(or can it just be omitted?)
|
(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');
|
$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
|
## Group membership service
|
||||||
|
|
||||||
**Service name**: `group.membership`
|
**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.
|
- 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
|
- With a computer mouse, you can use the scroll wheel to zoom in/out (click
|
||||||
on the map first to enable scroll zoom).
|
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
|
### Geolocating
|
||||||
|
|
||||||
|
|
|
@ -23,8 +23,9 @@ dependencies. The [farmOS Docker images](#farmos-in-docker) include these.
|
||||||
- `realpath_cache_size=4096K`
|
- `realpath_cache_size=4096K`
|
||||||
- `realpath_cache_ttl=3600`
|
- `realpath_cache_ttl=3600`
|
||||||
- **[PHP BCMath extension](https://www.php.net/manual/en/book.bc.php)** and
|
- **[PHP BCMath extension](https://www.php.net/manual/en/book.bc.php)** and
|
||||||
**[GEOS](https://trac.osgeo.org/geos)** are recommended for more accurate
|
**[GEOS](https://trac.osgeo.org/geos)** are required for accurate geometric
|
||||||
geometric calculations.
|
calculations. farmOS can be installed without these, but production usage
|
||||||
|
without them is strongly discouraged.
|
||||||
|
|
||||||
### Database server
|
### Database server
|
||||||
|
|
||||||
|
|
|
@ -30,7 +30,6 @@ function farm_modules() {
|
||||||
'farm_plant' => t('Plant assets'),
|
'farm_plant' => t('Plant assets'),
|
||||||
'farm_animal' => t('Animal assets'),
|
'farm_animal' => t('Animal assets'),
|
||||||
'farm_equipment' => t('Equipment assets'),
|
'farm_equipment' => t('Equipment assets'),
|
||||||
'farm_material' => t('Material assets'),
|
|
||||||
'farm_structure' => t('Structure assets'),
|
'farm_structure' => t('Structure assets'),
|
||||||
'farm_water' => t('Water assets'),
|
'farm_water' => t('Water assets'),
|
||||||
'farm_activity' => t('Activity logs'),
|
'farm_activity' => t('Activity logs'),
|
||||||
|
@ -46,6 +45,7 @@ function farm_modules() {
|
||||||
],
|
],
|
||||||
'optional' => [
|
'optional' => [
|
||||||
'farm_inventory' => t('Inventory management'),
|
'farm_inventory' => t('Inventory management'),
|
||||||
|
'farm_material' => t('Material assets'),
|
||||||
'farm_seed' => t('Seed assets'),
|
'farm_seed' => t('Seed assets'),
|
||||||
'farm_sensor' => t('Sensor assets'),
|
'farm_sensor' => t('Sensor assets'),
|
||||||
'farm_compost' => t('Compost assets'),
|
'farm_compost' => t('Compost assets'),
|
||||||
|
|
|
@ -351,7 +351,7 @@ class FarmFieldFactory implements FarmFieldFactoryInterface {
|
||||||
'type' => 'entity_reference_label',
|
'type' => 'entity_reference_label',
|
||||||
'weight' => $options['weight']['view'] ?? 0,
|
'weight' => $options['weight']['view'] ?? 0,
|
||||||
'settings' => [
|
'settings' => [
|
||||||
'link' => FALSE,
|
'link' => TRUE,
|
||||||
],
|
],
|
||||||
];
|
];
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -11,7 +11,7 @@ filters:
|
||||||
status: true
|
status: true
|
||||||
weight: -10
|
weight: -10
|
||||||
settings:
|
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_help: true
|
||||||
filter_html_nofollow: false
|
filter_html_nofollow: false
|
||||||
filter_autop:
|
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
|
base_route: farm_settings.settings_page
|
||||||
route_name: farm_settings.settings_page
|
route_name: farm_settings.settings_page
|
||||||
title: 'Farm Info'
|
title: 'Farm Info'
|
||||||
weight: -1
|
weight: -5
|
||||||
|
|
||||||
farm_settings.modules_form:
|
farm_settings.modules_form:
|
||||||
base_route: farm_settings.settings_page
|
base_route: farm_settings.settings_page
|
||||||
|
|
|
@ -2,8 +2,9 @@
|
||||||
Styling for the asset map_popup view mode page.
|
Styling for the asset map_popup view mode page.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* Remove the page background color. */
|
/* Remove the page background color and body top padding. */
|
||||||
body {
|
body.path-asset {
|
||||||
|
--ginHorizontalToolbarOffset: 0;
|
||||||
background: unset !important;
|
background: unset !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,10 +3,15 @@
|
||||||
* Styling for farmOS toolbar.
|
* 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. */
|
/* Logo size and spacing. */
|
||||||
.toolbar .toolbar-bar #toolbar-item-administration-tray .toolbar-logo img.toolbar-icon-home {
|
.toolbar .toolbar-bar #toolbar-item-administration-tray .toolbar-logo img.toolbar-icon-home {
|
||||||
max-width: 100px;
|
max-width: 100px;
|
||||||
margin: 40px auto;
|
margin: 20px auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Locations icon. */
|
/* Locations icon. */
|
||||||
|
|
|
@ -27,10 +27,11 @@ function farm_ui_theme_install() {
|
||||||
$gin_settings->set('preset_focus_color', 'orange');
|
$gin_settings->set('preset_focus_color', 'orange');
|
||||||
|
|
||||||
// Use farmOS logo and favicon.
|
// Use farmOS logo and favicon.
|
||||||
$gin_settings->set('icon_default', FALSE);
|
$path = \Drupal::service('extension.list.module')->getPath('farm_ui_theme');
|
||||||
$gin_settings->set('icon_path', drupal_get_path('module', 'farm_ui_theme') . '/logo.png');
|
$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.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.
|
// Save Gin settings.
|
||||||
$gin_settings->save();
|
$gin_settings->save();
|
||||||
|
@ -81,3 +82,15 @@ function farm_ui_theme_uninstall() {
|
||||||
$local_actions_block->set('settings.provider', 'core');
|
$local_actions_block->set('settings.provider', 'core');
|
||||||
$local_actions_block->save();
|
$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
|
- csv_serialization
|
||||||
- entity_browser
|
- entity_browser
|
||||||
- farm_location
|
- farm_location
|
||||||
|
- farm_ui_views
|
||||||
- image
|
- image
|
||||||
- options
|
- options
|
||||||
- rest
|
- rest
|
||||||
|
@ -1715,23 +1716,6 @@ display:
|
||||||
- url.query_args
|
- url.query_args
|
||||||
- user.permissions
|
- user.permissions
|
||||||
tags: { }
|
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'
|
default_action: 'not found'
|
||||||
exception:
|
exception:
|
||||||
value: all
|
value: all
|
||||||
|
@ -1746,38 +1730,117 @@ display:
|
||||||
summary_options:
|
summary_options:
|
||||||
base_path: ''
|
base_path: ''
|
||||||
count: true
|
count: true
|
||||||
override: false
|
|
||||||
items_per_page: 25
|
|
||||||
summary:
|
summary:
|
||||||
sort_order: asc
|
sort_order: asc
|
||||||
number_of_records: 0
|
number_of_records: 0
|
||||||
format: default_summary
|
format: default_summary
|
||||||
specify_validation: true
|
specify_validation: true
|
||||||
validate:
|
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'
|
fail: 'not found'
|
||||||
validate_options:
|
validate_options:
|
||||||
|
operation: view
|
||||||
access: false
|
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
|
operation: view
|
||||||
multiple: 0
|
multiple: 0
|
||||||
restrict_roles: false
|
access: false
|
||||||
roles: { }
|
bundles: { }
|
||||||
|
glossary: false
|
||||||
|
limit: 0
|
||||||
|
case: none
|
||||||
|
path_case: none
|
||||||
|
transform_dash: false
|
||||||
break_phrase: false
|
break_phrase: false
|
||||||
not: false
|
entity_type: asset
|
||||||
|
entity_field: type
|
||||||
|
plugin_id: string
|
||||||
defaults:
|
defaults:
|
||||||
arguments: false
|
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:
|
cache_metadata:
|
||||||
max-age: 0
|
max-age: 0
|
||||||
contexts:
|
contexts:
|
||||||
|
|
|
@ -2471,7 +2471,7 @@ display:
|
||||||
entity_type: log
|
entity_type: log
|
||||||
entity_field: type
|
entity_field: type
|
||||||
plugin_id: string
|
plugin_id: string
|
||||||
default_action: ignore
|
default_action: 'not found'
|
||||||
exception:
|
exception:
|
||||||
value: all
|
value: all
|
||||||
title_enable: false
|
title_enable: false
|
||||||
|
@ -2521,6 +2521,112 @@ display:
|
||||||
- user
|
- user
|
||||||
- user.permissions
|
- user.permissions
|
||||||
tags: { }
|
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:
|
page_type:
|
||||||
id: page_type
|
id: page_type
|
||||||
display_title: 'By type (page)'
|
display_title: 'By type (page)'
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
# Add log view tabs to assets.
|
||||||
farm.asset.logs:
|
farm.asset.logs:
|
||||||
title: 'Logs'
|
title: 'Logs'
|
||||||
route_name: view.farm_log.page_asset
|
route_name: view.farm_log.page_asset
|
||||||
|
@ -13,3 +14,21 @@ farm.asset.logs.all:
|
||||||
parent_id: farm.asset.logs
|
parent_id: farm.asset.logs
|
||||||
farm.asset.logs.type:
|
farm.asset.logs.type:
|
||||||
deriver: Drupal\farm_ui_views\Plugin\Derivative\FarmLogViewsTaskLink
|
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') {
|
elseif ($view->id() == 'farm_log' && $display_id == 'page_asset' && !empty($args[1]) && $args[1] != 'all') {
|
||||||
$bundle = $args[1];
|
$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;
|
return $bundle;
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,6 +13,24 @@ services:
|
||||||
arguments: [ '@entity_type.manager', '@asset.location' ]
|
arguments: [ '@entity_type.manager', '@asset.location' ]
|
||||||
tags:
|
tags:
|
||||||
- { name: access_check, applies_to: _asset_children_access }
|
- { 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:
|
farm_ui_views.asset_inventory_access:
|
||||||
class: Drupal\farm_ui_views\Access\FarmInventoryAssetViewsAccessCheck
|
class: Drupal\farm_ui_views\Access\FarmInventoryAssetViewsAccessCheck
|
||||||
arguments: [ '@entity_type.manager' ]
|
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.
|
// Set the title, if so desired.
|
||||||
if (!empty($title)) {
|
if (!empty($title)) {
|
||||||
$view->setTitle($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');
|
$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
|
// Add our _location_assets_access requirement to
|
||||||
// view.farm_asset.page_location.
|
// view.farm_asset.page_location.
|
||||||
if ($route = $collection->get('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