diff --git a/.drone.yml b/.drone.yml index 6f52ca3..f467229 100644 --- a/.drone.yml +++ b/.drone.yml @@ -3,40 +3,105 @@ kind: pipeline name: default steps: - - name: weblinks-codeception-tests - image: joomlaprojects/docker-images:systemtests + - name: composer + image: joomlaprojects/docker-images:php8.2 + volumes: + - name: composer-cache + path: /tmp/composer-cache commands: - - pwd - - composer install - - chmod a+x .drone/build.sh - - ./.drone/build.sh - - apache2ctl start - - service mysql start - - cd /tests/www - - export DISPLAY=:0 - - Xvfb -screen 0 1024x768x24 -ac +extension GLX +render -noreset > /dev/null 2>&1 & - - sleep 3 - - fluxbox > /dev/null 2>&1 & - - vendor/bin/robo run:tests + - composer install --no-progress - - name: artifacts-codeception-tests - image: cschlosser/drone-ftps - depends_on: [ weblinks-codeception-tests ] + - name: phpcs + image: joomlaprojects/docker-images:php8.1 + depends_on: [ composer ] + commands: + - echo $(date) + - ./vendor/bin/php-cs-fixer fix -vvv --dry-run --diff + - ./vendor/bin/phpcs --extensions=php -p --standard=ruleset.xml src/ + - echo $(date) + + - name: npm + image: node:16-bullseye-slim + depends_on: [ phpcs ] + volumes: + - name: npm-cache + path: /tmp/npm-cache + environment: + npm_config_cache: /tmp/npm-cache + commands: + - npm i --unsafe-perm + + - name: prepare_system_tests + depends_on: [ npm ] + image: joomlaprojects/docker-images:systemtests + volumes: + - name: cypress-cache + path: /root/.cache/Cypress + commands: + - mv cypress.config.dist.js cypress.config.js + - npx cypress install + - npx cypress verify + - vendor/bin/robo build + - curl https://joomla.org/latest -L --output joomla.zip + - mkdir joomla + - cp joomla.zip joomla/joomla.zip + - cd joomla + - unzip joomla.zip + + - name: phan + image: joomlaprojects/docker-images:php8.1-ast + depends_on: [ prepare_system_tests ] + failure: ignore + commands: + - vendor/bin/phan + + - name: phpstan + image: joomlaprojects/docker-images:php8.1 + depends_on: [ prepare_system_tests ] + failure: ignore + commands: + - vendor/bin/phpstan analyse src + + - name: phpmin-system-mysql + depends_on: [ prepare_system_tests ] + image: joomlaprojects/docker-images:cypress + volumes: + - name: cypress-cache + path: /root/.cache/Cypress + commands: + - mkdir /tests/www/mysql/ + - cp joomla.zip /tests/www/mysql/joomla.zip + - cp dist/pkg-weblinks-current.zip /tests/www/mysql/pkg-weblinks-current.zip + - cd /tests/www/mysql/ + - unzip joomla.zip + - apache2ctl -D FOREGROUND & + - chmod +rwx /root + - php installation/joomla.php install --verbose --site-name="Joomla CMS test" --admin-email=admin@example.org --admin-username=ci-admin --admin-user="jane doe" --admin-password=joomla-17082005 --db-type=mysqli --db-host=mysql --db-name=test_joomla --db-pass=joomla_ut --db-user=root --db-encryption=0 --db-prefix=mysql_ + - php cli/joomla.php config:set debug=true error_reporting=maximum + - php cli/joomla.php extension:install --path=/tests/www/mysql/pkg-weblinks-current.zip + - chmod -R 777 /tests/www/mysql/ + - chown -R www-data /tests/www/mysql/ + - cd /drone/src + - npx cypress run --browser=firefox --e2e --config baseUrl=http://localhost/mysql,screenshotsFolder=/drone/src/tests/cypress/output/screenshots + + - name: artifacts-system-tests + image: joomlaprojects/docker-images:packager + depends_on: + - phpmin-system-mysql environment: FTP_USERNAME: from_secret: ftpusername FTP_PASSWORD: from_secret: ftppassword - PLUGIN_HOSTNAME: artifacts.joomla.org:21 - PLUGIN_SRC_DIR: /tests/_output - PLUGIN_DEST_DIR: / - PLUGIN_SECURE: false - PLUGIN_EXCLUDE: ^\.git/$ + GITHUB_TOKEN: + from_secret: github_token commands: - - ls -l /drone/src/tests/_output - - export PLUGIN_DEST_DIR=$PLUGIN_DEST_DIR/$DRONE_REPO/$DRONE_BRANCH/$DRONE_PULL_REQUEST/system-tests/$DRONE_BUILD_NUMBER - - echo https://artifacts.joomla.org/drone$PLUGIN_DEST_DIR - - /bin/upload.sh + - export PLUGIN_DEST_DIR=/artifacts/$DRONE_REPO/$DRONE_BRANCH/$DRONE_PULL_REQUEST/system-tests/$DRONE_BUILD_NUMBER + - echo https://ci.joomla.org$PLUGIN_DEST_DIR + - rclone config create artifacts ftp host ci.joomla.org user $FTP_USERNAME port 21 pass $FTP_PASSWORD + - rclone mkdir artifacts:$PLUGIN_DEST_DIR + - rclone copy tests/cypress/output/ artifacts:$PLUGIN_DEST_DIR + - 'curl -X POST "https://api.github.com/repos/$DRONE_REPO/statuses/$DRONE_COMMIT" -H "Content-Type: application/json" -H "Authorization: token $GITHUB_TOKEN" -d "{\"state\":\"failure\", \"context\": \"Artifacts from Failure\", \"description\": \"You can find artifacts from the failure of the build here:\", \"target_url\": \"https://ci.joomla.org$PLUGIN_DEST_DIR\"}" > /dev/null' when: status: - failure @@ -45,9 +110,45 @@ volumes: - name: weblinks_cache host: path: /tmp/weblinks_cache + - name: composer-cache + host: + path: /tmp/composer-cache + - name: cypress-cache + host: + path: /tmp/cypress-cache + - name: npm-cache + host: + path: /tmp/npm-cache + +services: + - name: mysql + image: mysql:5.7 + environment: + MYSQL_USER: joomla_ut + MYSQL_PASSWORD: joomla_ut + MYSQL_ROOT_PASSWORD: joomla_ut + MYSQL_DATABASE: test_joomla + + - name: mysql8 + image: mysql:8 + command: ["--default-authentication-plugin=mysql_native_password"] + environment: + MYSQL_USER: joomla_ut + MYSQL_PASSWORD: joomla_ut + MYSQL_ROOT_PASSWORD: joomla_ut + MYSQL_DATABASE: test_joomla + + - name: postgres + image: postgres:11-alpine + ports: + - 5432 + environment: + POSTGRES_USER: root + POSTGRES_PASSWORD: joomla_ut + POSTGRES_DB: test_joomla --- kind: signature -hmac: bcc028d5d9601f1f3355862f17dd2434ba86f47634f0737877db534e49c8265b +hmac: 8b2b4e6fe85da897755c46d961b49c1e53a13e5a2cf6df5cde70aa07233b2494 ... diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..dd23145 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,20 @@ +# EditorConfig is awesome: https://EditorConfig.org + +# top-most EditorConfig file +root = true + +# Unix-style end of lines and a blank line at the end of the file +[*] +indent_style = tab +end_of_line = lf +charset = utf-8 +trim_trailing_whitespace = true +insert_final_newline = true + +[*.php] +indent_style = space +indent_size = 4 + +[*.{js,json,scss,css,yml,vue}] +indent_style = space +indent_size = 2 diff --git a/.gitignore b/.gitignore index 206a30d..f7f9767 100644 --- a/.gitignore +++ b/.gitignore @@ -1,64 +1,73 @@ -# Builds -build -releases - -# OSX -.DS_Store -._* -.Spotlight-V100 -.Trashes - -# Windows -Thumbs.db -Desktop.ini - -# PHPStorm -.idea/ - -# Sublime Text -*.sublime* - -# Eclipse -.buildpath -.project -.settings - -# Temp files -*.tmp -*.bak -*.swp -*~.nib -*~ - -# Phing -build.properties -phing-latest.phar - -# Github pages and Jekyll files -/_site/ -/Gemfile -/Gemfile.lock - -# composer -composer.phar -vendor/* - -# Robo -robo.phar -RoboFile.ini - -# Test related files -tests/acceptance.suite.yml -tests/*/*Tester.php -tests/_support/_generated/*TesterActions.php -tests/joomla* -tests/_output* -selenium-server-standalone.jar -codecept.phar -selenium.log -tests/cache - -# Package building related -/dist -jorobo.ini - +# Builds +build +releases + +# OSX +.DS_Store +._* +.Spotlight-V100 +.Trashes + +# Windows +Thumbs.db +Desktop.ini + +# PHPStorm +.idea/ + +# Sublime Text +*.sublime* + +# Eclipse +.buildpath +.project +.settings + +# Temp files +*.tmp +*.bak +*.swp +*~.nib +*~ + +# Phing +build.properties +phing-latest.phar + +# Github pages and Jekyll files +/_site/ +/Gemfile +/Gemfile.lock + +# composer +composer.phar +vendor/* + +# Robo +robo.phar +RoboFile.ini + +# Test related files +tests/acceptance.suite.yml +tests/*/*Tester.php +tests/_support/_generated/*TesterActions.php +tests/joomla* +tests/_output* +selenium-server-standalone.jar +codecept.phar +selenium.log +tests/cache + +#cypress +node_modules +/tests/cypress/output/screenshots +!/tests/cypress/output/screenshots/.gitkeep +/tests/cypress/output/videos +!/tests/cypress/output/videos/.gitkeep +cypress.config.js +joomla + +# Package building related +/dist +jorobo.ini + diff --git a/.phan/config.php b/.phan/config.php index 33f9693..bda9b76 100644 --- a/.phan/config.php +++ b/.phan/config.php @@ -291,7 +291,8 @@ return [ // should be added to the `directory_list` as well as // to `exclude_analysis_directory_list`. 'exclude_analysis_directory_list' => [ - 'tests/joomla' + 'joomla/administrator/components/com_finder/src/Indexer', + 'joomla/libraries' ], // Enable this to enable checks of require/include statements referring to valid paths. @@ -338,7 +339,8 @@ return [ // your application should be included in this list. 'directory_list' => [ 'src', - 'tests/joomla' + 'joomla/administrator/components/com_finder/src/Indexer', + 'joomla/libraries' ], // A list of individual files to include in analysis diff --git a/.php-cs-fixer.dist.php b/.php-cs-fixer.dist.php new file mode 100644 index 0000000..a658ca5 --- /dev/null +++ b/.php-cs-fixer.dist.php @@ -0,0 +1,67 @@ + + * @license GNU General Public License version 2 or later; see LICENSE.txt + */ + +/** + * This is the configuration file for php-cs-fixer + * + * @see https://github.com/FriendsOfPHP/PHP-CS-Fixer + * @see https://mlocati.github.io/php-cs-fixer-configurator/#version:3.0 + * + * + * If you would like to run the automated clean up, then open a command line and type one of the commands below + * + * To run a quick dry run to see the files that would be modified: + * + * ./component/backend/vendor/bin/php-cs-fixer fix --dry-run + * + * To run a full check, with automated fixing of each problem : + * + * ./component/backend/vendor/bin/php-cs-fixer fix + * + * You can run the clean up on a single file if you need to, this is faster + * + * ./component/backend/vendor/bin/php-cs-fixer fix --dry-run administrator/index.php + * ./component/backend/vendor/bin/php-cs-fixer fix administrator/index.php + */ + +// Add all the core Joomla folders +$finder = PhpCsFixer\Finder::create() + ->in( + [ + __DIR__ . '/src', + ] + ) + // Ignore template files as PHP CS fixer can't handle them properly + // https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/issues/3702#issuecomment-396717120 + ->notPath('/vendor/') + ->notPath('/tmpl/'); + +$config = new PhpCsFixer\Config(); +$config + ->setRiskyAllowed(true) + ->setHideProgress(false) + ->setUsingCache(false) + ->setRules( + [ + // Basic ruleset is PSR 12 + '@PSR12' => true, + // Short array syntax + 'array_syntax' => ['syntax' => 'short'], + // Lists should not have a trailing comma like list($foo, $bar,) = ... + 'no_trailing_comma_in_list_call' => true, + // Arrays on multiline should have a trailing comma + 'trailing_comma_in_multiline' => ['elements' => ['arrays']], + // Align elements in multiline array and variable declarations on new lines below each other + 'binary_operator_spaces' => ['operators' => ['=>' => 'align_single_space_minimal', '=' => 'align']], + // The "No break" comment in switch statements + 'no_break_comment' => ['comment_text' => 'No break'], + ] + ) + ->setFinder($finder); + +return $config; diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index bd378b6..0000000 --- a/.travis.yml +++ /dev/null @@ -1,49 +0,0 @@ -sudo: true -language: php -services: - - xvfb - -env: - global: - - RUN_PHPCS="no" - -matrix: - fast_finish: true - include: - - php: 7.2 - sudo: true - env: RUN_PHPCS="yes" - - php: 7.3 - -before_script: -# Forcing localhost in hosts file -- sudo sed -i '1s/^/127.0.0.1 localhost\n/' /etc/hosts -- sudo apt-get update -qq -- sudo apt-get install -y --force-yes apache2 libapache2-mod-fastcgi > /dev/null -- sudo mkdir $(pwd)/.run -- chmod a+x tests/travis-php-fpm.sh -- sudo ./tests/travis-php-fpm.sh $USER $(phpenv version-name) -- sudo a2enmod rewrite actions fastcgi alias -- echo "cgi.fix_pathinfo = 1" >> ~/.phpenv/versions/$(phpenv version-name)/etc/php.ini -- ~/.phpenv/versions/$(phpenv version-name)/sbin/php-fpm -- sudo cp -f tests/travis-ci-apache.conf /etc/apache2/sites-available/default -- sudo sed -e "s?%TRAVIS_BUILD_DIR%?$(pwd)?g" --in-place /etc/apache2/sites-available/default -- sudo sed -e "s?%PHPVERSION%?${TRAVIS_PHP_VERSION:0:1}?g" --in-place /etc/apache2/sites-available/default -- git submodule update --init --recursive -- sudo service apache2 restart -# Fluxbox -- sudo apt-get install fluxbox -y --force-yes -- fluxbox & -- sleep 3 # give fluxbox some time to start -# Composer -- composer install - -script: -# Build -- mv jorobo.dist.ini jorobo.ini -- vendor/bin/robo build -# System tests (Codeception) -- mv tests/acceptance.suite.dist.yml tests/acceptance.suite.yml -- vendor/bin/robo run:tests --use-htaccess -# Run phpcs on flagged php versions against weblinks source -- if [[ $RUN_PHPCS == "yes" ]]; then vendor/bin/phpcs --report=full --extensions=php -p --standard=tests/joomla/build/phpcs/Joomla ./src; fi diff --git a/composer.json b/composer.json index 702877e..95fc26b 100644 --- a/composer.json +++ b/composer.json @@ -19,6 +19,8 @@ "joomla-projects/jorobo": "dev-develop", "joomla-projects/selenium-server-standalone": "^3.14", "phpunit/phpunit": "^5.7.27", + "friendsofphp/php-cs-fixer": "^3.4.0", + "squizlabs/php_codesniffer": "^3.7.1", "codeception/module-filesystem": "^1.0", "codeception/module-asserts": "^1.3", "phpstan/phpstan": "^1.10", diff --git a/composer.lock b/composer.lock index 7ff310d..7358279 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "a5269e8ba3b32ffc908f41e3301bb68c", + "content-hash": "5d1d209f067fc75fbbc014518681134a", "packages": [], "packages-dev": [ { @@ -546,30 +546,30 @@ }, { "name": "composer/pcre", - "version": "2.1.0", + "version": "1.0.1", "source": { "type": "git", "url": "https://github.com/composer/pcre.git", - "reference": "3fdb2807b31a78a40ad89570e30ec77466c98717" + "reference": "67a32d7d6f9f560b726ab25a061b38ff3a80c560" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/pcre/zipball/3fdb2807b31a78a40ad89570e30ec77466c98717", - "reference": "3fdb2807b31a78a40ad89570e30ec77466c98717", + "url": "https://api.github.com/repos/composer/pcre/zipball/67a32d7d6f9f560b726ab25a061b38ff3a80c560", + "reference": "67a32d7d6f9f560b726ab25a061b38ff3a80c560", "shasum": "" }, "require": { - "php": "^7.2 || ^8.0" + "php": "^5.3.2 || ^7.0 || ^8.0" }, "require-dev": { "phpstan/phpstan": "^1.3", "phpstan/phpstan-strict-rules": "^1.1", - "symfony/phpunit-bridge": "^5" + "symfony/phpunit-bridge": "^4.2 || ^5" }, "type": "library", "extra": { "branch-alias": { - "dev-main": "2.x-dev" + "dev-main": "1.x-dev" } }, "autoload": { @@ -597,7 +597,7 @@ ], "support": { "issues": "https://github.com/composer/pcre/issues", - "source": "https://github.com/composer/pcre/tree/2.1.0" + "source": "https://github.com/composer/pcre/tree/1.0.1" }, "funding": [ { @@ -613,7 +613,7 @@ "type": "tidelift" } ], - "time": "2022-11-16T18:32:04+00:00" + "time": "2022-01-21T20:24:37+00:00" }, { "name": "composer/semver", @@ -698,27 +698,27 @@ }, { "name": "composer/xdebug-handler", - "version": "3.0.3", + "version": "2.0.5", "source": { "type": "git", "url": "https://github.com/composer/xdebug-handler.git", - "reference": "ced299686f41dce890debac69273b47ffe98a40c" + "reference": "9e36aeed4616366d2b690bdce11f71e9178c579a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/xdebug-handler/zipball/ced299686f41dce890debac69273b47ffe98a40c", - "reference": "ced299686f41dce890debac69273b47ffe98a40c", + "url": "https://api.github.com/repos/composer/xdebug-handler/zipball/9e36aeed4616366d2b690bdce11f71e9178c579a", + "reference": "9e36aeed4616366d2b690bdce11f71e9178c579a", "shasum": "" }, "require": { - "composer/pcre": "^1 || ^2 || ^3", - "php": "^7.2.5 || ^8.0", + "composer/pcre": "^1", + "php": "^5.3.2 || ^7.0 || ^8.0", "psr/log": "^1 || ^2 || ^3" }, "require-dev": { "phpstan/phpstan": "^1.0", "phpstan/phpstan-strict-rules": "^1.1", - "symfony/phpunit-bridge": "^6.0" + "symfony/phpunit-bridge": "^4.2 || ^5.0 || ^6.0" }, "type": "library", "autoload": { @@ -744,7 +744,7 @@ "support": { "irc": "irc://irc.freenode.org/composer", "issues": "https://github.com/composer/xdebug-handler/issues", - "source": "https://github.com/composer/xdebug-handler/tree/3.0.3" + "source": "https://github.com/composer/xdebug-handler/tree/2.0.5" }, "funding": [ { @@ -760,7 +760,7 @@ "type": "tidelift" } ], - "time": "2022-02-25T21:32:43+00:00" + "time": "2022-02-24T20:20:32+00:00" }, { "name": "consolidation/annotated-command", @@ -1213,6 +1213,125 @@ }, "time": "2022-10-27T11:44:00+00:00" }, + { + "name": "doctrine/annotations", + "version": "1.14.3", + "source": { + "type": "git", + "url": "https://github.com/doctrine/annotations.git", + "reference": "fb0d71a7393298a7b232cbf4c8b1f73f3ec3d5af" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/annotations/zipball/fb0d71a7393298a7b232cbf4c8b1f73f3ec3d5af", + "reference": "fb0d71a7393298a7b232cbf4c8b1f73f3ec3d5af", + "shasum": "" + }, + "require": { + "doctrine/lexer": "^1 || ^2", + "ext-tokenizer": "*", + "php": "^7.1 || ^8.0", + "psr/cache": "^1 || ^2 || ^3" + }, + "require-dev": { + "doctrine/cache": "^1.11 || ^2.0", + "doctrine/coding-standard": "^9 || ^10", + "phpstan/phpstan": "~1.4.10 || ^1.8.0", + "phpunit/phpunit": "^7.5 || ^8.5 || ^9.5", + "symfony/cache": "^4.4 || ^5.4 || ^6", + "vimeo/psalm": "^4.10" + }, + "suggest": { + "php": "PHP 8.0 or higher comes with attributes, a native replacement for annotations" + }, + "type": "library", + "autoload": { + "psr-4": { + "Doctrine\\Common\\Annotations\\": "lib/Doctrine/Common/Annotations" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Guilherme Blanco", + "email": "guilhermeblanco@gmail.com" + }, + { + "name": "Roman Borschel", + "email": "roman@code-factory.org" + }, + { + "name": "Benjamin Eberlei", + "email": "kontakt@beberlei.de" + }, + { + "name": "Jonathan Wage", + "email": "jonwage@gmail.com" + }, + { + "name": "Johannes Schmitt", + "email": "schmittjoh@gmail.com" + } + ], + "description": "Docblock Annotations Parser", + "homepage": "https://www.doctrine-project.org/projects/annotations.html", + "keywords": [ + "annotations", + "docblock", + "parser" + ], + "support": { + "issues": "https://github.com/doctrine/annotations/issues", + "source": "https://github.com/doctrine/annotations/tree/1.14.3" + }, + "time": "2023-02-01T09:20:38+00:00" + }, + { + "name": "doctrine/deprecations", + "version": "v1.0.0", + "source": { + "type": "git", + "url": "https://github.com/doctrine/deprecations.git", + "reference": "0e2a4f1f8cdfc7a92ec3b01c9334898c806b30de" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/deprecations/zipball/0e2a4f1f8cdfc7a92ec3b01c9334898c806b30de", + "reference": "0e2a4f1f8cdfc7a92ec3b01c9334898c806b30de", + "shasum": "" + }, + "require": { + "php": "^7.1|^8.0" + }, + "require-dev": { + "doctrine/coding-standard": "^9", + "phpunit/phpunit": "^7.5|^8.5|^9.5", + "psr/log": "^1|^2|^3" + }, + "suggest": { + "psr/log": "Allows logging deprecations via PSR-3 logger implementation" + }, + "type": "library", + "autoload": { + "psr-4": { + "Doctrine\\Deprecations\\": "lib/Doctrine/Deprecations" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "A small layer on top of trigger_error(E_USER_DEPRECATED) or PSR-3 logging with options to disable all deprecations or selectively for packages.", + "homepage": "https://www.doctrine-project.org/", + "support": { + "issues": "https://github.com/doctrine/deprecations/issues", + "source": "https://github.com/doctrine/deprecations/tree/v1.0.0" + }, + "time": "2022-05-02T15:47:09+00:00" + }, { "name": "doctrine/instantiator", "version": "1.5.0", @@ -1283,6 +1402,84 @@ ], "time": "2022-12-30T00:15:36+00:00" }, + { + "name": "doctrine/lexer", + "version": "2.1.0", + "source": { + "type": "git", + "url": "https://github.com/doctrine/lexer.git", + "reference": "39ab8fcf5a51ce4b85ca97c7a7d033eb12831124" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/lexer/zipball/39ab8fcf5a51ce4b85ca97c7a7d033eb12831124", + "reference": "39ab8fcf5a51ce4b85ca97c7a7d033eb12831124", + "shasum": "" + }, + "require": { + "doctrine/deprecations": "^1.0", + "php": "^7.1 || ^8.0" + }, + "require-dev": { + "doctrine/coding-standard": "^9 || ^10", + "phpstan/phpstan": "^1.3", + "phpunit/phpunit": "^7.5 || ^8.5 || ^9.5", + "psalm/plugin-phpunit": "^0.18.3", + "vimeo/psalm": "^4.11 || ^5.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Doctrine\\Common\\Lexer\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Guilherme Blanco", + "email": "guilhermeblanco@gmail.com" + }, + { + "name": "Roman Borschel", + "email": "roman@code-factory.org" + }, + { + "name": "Johannes Schmitt", + "email": "schmittjoh@gmail.com" + } + ], + "description": "PHP Doctrine Lexer parser library that can be used in Top-Down, Recursive Descent Parsers.", + "homepage": "https://www.doctrine-project.org/projects/lexer.html", + "keywords": [ + "annotations", + "docblock", + "lexer", + "parser", + "php" + ], + "support": { + "issues": "https://github.com/doctrine/lexer/issues", + "source": "https://github.com/doctrine/lexer/tree/2.1.0" + }, + "funding": [ + { + "url": "https://www.doctrine-project.org/sponsorship.html", + "type": "custom" + }, + { + "url": "https://www.patreon.com/phpdoctrine", + "type": "patreon" + }, + { + "url": "https://tidelift.com/funding/github/packagist/doctrine%2Flexer", + "type": "tidelift" + } + ], + "time": "2022-12-14T08:49:07+00:00" + }, { "name": "felixfbecker/advanced-json-rpc", "version": "v3.2.1", @@ -1328,6 +1525,95 @@ }, "time": "2021-06-11T22:34:44+00:00" }, + { + "name": "friendsofphp/php-cs-fixer", + "version": "v3.4.0", + "source": { + "type": "git", + "url": "https://github.com/FriendsOfPHP/PHP-CS-Fixer.git", + "reference": "47177af1cfb9dab5d1cc4daf91b7179c2efe7fad" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/FriendsOfPHP/PHP-CS-Fixer/zipball/47177af1cfb9dab5d1cc4daf91b7179c2efe7fad", + "reference": "47177af1cfb9dab5d1cc4daf91b7179c2efe7fad", + "shasum": "" + }, + "require": { + "composer/semver": "^3.2", + "composer/xdebug-handler": "^2.0", + "doctrine/annotations": "^1.12", + "ext-json": "*", + "ext-tokenizer": "*", + "php": "^7.2.5 || ^8.0", + "php-cs-fixer/diff": "^2.0", + "symfony/console": "^4.4.20 || ^5.1.3 || ^6.0", + "symfony/event-dispatcher": "^4.4.20 || ^5.0 || ^6.0", + "symfony/filesystem": "^4.4.20 || ^5.0 || ^6.0", + "symfony/finder": "^4.4.20 || ^5.0 || ^6.0", + "symfony/options-resolver": "^4.4.20 || ^5.0 || ^6.0", + "symfony/polyfill-mbstring": "^1.23", + "symfony/polyfill-php80": "^1.23", + "symfony/polyfill-php81": "^1.23", + "symfony/process": "^4.4.20 || ^5.0 || ^6.0", + "symfony/stopwatch": "^4.4.20 || ^5.0 || ^6.0" + }, + "require-dev": { + "justinrainbow/json-schema": "^5.2", + "keradus/cli-executor": "^1.5", + "mikey179/vfsstream": "^1.6.8", + "php-coveralls/php-coveralls": "^2.5.2", + "php-cs-fixer/accessible-object": "^1.1", + "php-cs-fixer/phpunit-constraint-isidenticalstring": "^1.2", + "php-cs-fixer/phpunit-constraint-xmlmatchesxsd": "^1.2.1", + "phpspec/prophecy": "^1.15", + "phpspec/prophecy-phpunit": "^1.1 || ^2.0", + "phpunit/phpunit": "^8.5.21 || ^9.5", + "phpunitgoodpractices/polyfill": "^1.5", + "phpunitgoodpractices/traits": "^1.9.1", + "symfony/phpunit-bridge": "^5.2.4 || ^6.0", + "symfony/yaml": "^4.4.20 || ^5.0 || ^6.0" + }, + "suggest": { + "ext-dom": "For handling output formats in XML", + "ext-mbstring": "For handling non-UTF8 characters." + }, + "bin": [ + "php-cs-fixer" + ], + "type": "application", + "autoload": { + "psr-4": { + "PhpCsFixer\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Dariusz RumiƄski", + "email": "dariusz.ruminski@gmail.com" + } + ], + "description": "A tool to automatically fix PHP code style", + "support": { + "issues": "https://github.com/FriendsOfPHP/PHP-CS-Fixer/issues", + "source": "https://github.com/FriendsOfPHP/PHP-CS-Fixer/tree/v3.4.0" + }, + "funding": [ + { + "url": "https://github.com/keradus", + "type": "github" + } + ], + "time": "2021-12-11T16:25:08+00:00" + }, { "name": "fzaninotto/faker", "version": "v1.9.2", @@ -2660,6 +2946,59 @@ }, "time": "2023-03-03T17:20:24+00:00" }, + { + "name": "php-cs-fixer/diff", + "version": "v2.0.2", + "source": { + "type": "git", + "url": "https://github.com/PHP-CS-Fixer/diff.git", + "reference": "29dc0d507e838c4580d018bd8b5cb412474f7ec3" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/PHP-CS-Fixer/diff/zipball/29dc0d507e838c4580d018bd8b5cb412474f7ec3", + "reference": "29dc0d507e838c4580d018bd8b5cb412474f7ec3", + "shasum": "" + }, + "require": { + "php": "^5.6 || ^7.0 || ^8.0" + }, + "require-dev": { + "phpunit/phpunit": "^5.7.23 || ^6.4.3 || ^7.0", + "symfony/process": "^3.3" + }, + "type": "library", + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Kore Nordmann", + "email": "mail@kore-nordmann.de" + } + ], + "description": "sebastian/diff v3 backport support for PHP 5.6+", + "homepage": "https://github.com/PHP-CS-Fixer", + "keywords": [ + "diff" + ], + "support": { + "issues": "https://github.com/PHP-CS-Fixer/diff/issues", + "source": "https://github.com/PHP-CS-Fixer/diff/tree/v2.0.2" + }, + "abandoned": true, + "time": "2020-10-14T08:32:19+00:00" + }, { "name": "php-webdriver/webdriver", "version": "1.13.1", @@ -3485,6 +3824,55 @@ "abandoned": true, "time": "2017-06-30T09:13:00+00:00" }, + { + "name": "psr/cache", + "version": "1.0.1", + "source": { + "type": "git", + "url": "https://github.com/php-fig/cache.git", + "reference": "d11b50ad223250cf17b86e38383413f5a6764bf8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/cache/zipball/d11b50ad223250cf17b86e38383413f5a6764bf8", + "reference": "d11b50ad223250cf17b86e38383413f5a6764bf8", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Cache\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Common interface for caching libraries", + "keywords": [ + "cache", + "psr", + "psr-6" + ], + "support": { + "source": "https://github.com/php-fig/cache/tree/master" + }, + "time": "2016-08-06T20:24:11+00:00" + }, { "name": "psr/container", "version": "2.0.1", @@ -4467,6 +4855,63 @@ }, "time": "2016-10-03T07:35:21+00:00" }, + { + "name": "squizlabs/php_codesniffer", + "version": "3.7.2", + "source": { + "type": "git", + "url": "https://github.com/squizlabs/PHP_CodeSniffer.git", + "reference": "ed8e00df0a83aa96acf703f8c2979ff33341f879" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/squizlabs/PHP_CodeSniffer/zipball/ed8e00df0a83aa96acf703f8c2979ff33341f879", + "reference": "ed8e00df0a83aa96acf703f8c2979ff33341f879", + "shasum": "" + }, + "require": { + "ext-simplexml": "*", + "ext-tokenizer": "*", + "ext-xmlwriter": "*", + "php": ">=5.4.0" + }, + "require-dev": { + "phpunit/phpunit": "^4.0 || ^5.0 || ^6.0 || ^7.0" + }, + "bin": [ + "bin/phpcs", + "bin/phpcbf" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.x-dev" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Greg Sherwood", + "role": "lead" + } + ], + "description": "PHP_CodeSniffer tokenizes PHP, JavaScript and CSS files and detects violations of a defined set of coding standards.", + "homepage": "https://github.com/squizlabs/PHP_CodeSniffer", + "keywords": [ + "phpcs", + "standards", + "static analysis" + ], + "support": { + "issues": "https://github.com/squizlabs/PHP_CodeSniffer/issues", + "source": "https://github.com/squizlabs/PHP_CodeSniffer", + "wiki": "https://github.com/squizlabs/PHP_CodeSniffer/wiki" + }, + "time": "2023-02-22T23:07:41+00:00" + }, { "name": "symfony/console", "version": "v5.4.23", @@ -4990,6 +5435,75 @@ ], "time": "2023-02-16T09:33:00+00:00" }, + { + "name": "symfony/options-resolver", + "version": "v5.4.21", + "source": { + "type": "git", + "url": "https://github.com/symfony/options-resolver.git", + "reference": "4fe5cf6ede71096839f0e4b4444d65dd3a7c1eb9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/options-resolver/zipball/4fe5cf6ede71096839f0e4b4444d65dd3a7c1eb9", + "reference": "4fe5cf6ede71096839f0e4b4444d65dd3a7c1eb9", + "shasum": "" + }, + "require": { + "php": ">=7.2.5", + "symfony/deprecation-contracts": "^2.1|^3", + "symfony/polyfill-php73": "~1.0", + "symfony/polyfill-php80": "^1.16" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\OptionsResolver\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides an improved replacement for the array_replace PHP function", + "homepage": "https://symfony.com", + "keywords": [ + "config", + "configuration", + "options" + ], + "support": { + "source": "https://github.com/symfony/options-resolver/tree/v5.4.21" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2023-02-14T08:03:56+00:00" + }, { "name": "symfony/polyfill-ctype", "version": "v1.27.0", @@ -5482,6 +5996,85 @@ ], "time": "2022-11-03T14:55:06+00:00" }, + { + "name": "symfony/polyfill-php81", + "version": "v1.27.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php81.git", + "reference": "707403074c8ea6e2edaf8794b0157a0bfa52157a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php81/zipball/707403074c8ea6e2edaf8794b0157a0bfa52157a", + "reference": "707403074c8ea6e2edaf8794b0157a0bfa52157a", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.27-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Php81\\": "" + }, + "classmap": [ + "Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill backporting some PHP 8.1+ features to lower PHP versions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-php81/tree/v1.27.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-11-03T14:55:06+00:00" + }, { "name": "symfony/process", "version": "v5.4.23", @@ -5605,6 +6198,68 @@ }, "time": "2019-05-28T07:50:59+00:00" }, + { + "name": "symfony/stopwatch", + "version": "v5.4.21", + "source": { + "type": "git", + "url": "https://github.com/symfony/stopwatch.git", + "reference": "f83692cd869a6f2391691d40a01e8acb89e76fee" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/stopwatch/zipball/f83692cd869a6f2391691d40a01e8acb89e76fee", + "reference": "f83692cd869a6f2391691d40a01e8acb89e76fee", + "shasum": "" + }, + "require": { + "php": ">=7.2.5", + "symfony/service-contracts": "^1|^2|^3" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Stopwatch\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides a way to profile code", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/stopwatch/tree/v5.4.21" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2023-02-14T08:03:56+00:00" + }, { "name": "symfony/string", "version": "v5.4.22", diff --git a/cypress.config.dist.js b/cypress.config.dist.js new file mode 100644 index 0000000..1cdb906 --- /dev/null +++ b/cypress.config.dist.js @@ -0,0 +1,36 @@ +const { defineConfig } = require('cypress') + +module.exports = defineConfig({ + fixturesFolder: 'tests/cypress/fixtures', + videosFolder: 'tests/cypress/output/videos', + screenshotsFolder: 'tests/cypress/output/screenshots', + viewportHeight: 1000, + viewportWidth: 1200, + e2e: { + setupNodeEvents(on, config) {}, + baseUrl: 'http://localhost/', + specPattern: [ + 'tests/cypress/integration/install/*.cy.{js,jsx,ts,tsx}', + 'tests/cypress/integration/administrator/**/*.cy.{js,jsx,ts,tsx}', + 'tests/cypress/integration/site/**/*.cy.{js,jsx,ts,tsx}' + ], + supportFile: 'tests/cypress/support/index.js', + scrollBehavior: 'center', + browser: 'firefox', + screenshotOnRunFailure: true, + video: false + }, + env: { + sitename: 'Joomla CMS Test', + name: 'jane doe', + email: 'admin@example.com', + username: 'ci-admin', + password: 'joomla-17082005', + db_type: 'MySQLi', + db_host: 'localhost', + db_name: 'test_joomla', + db_user: 'root', + db_password: 'joomla_ut', + db_prefix: 'jos_', + }, +}) diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..4de0d6e --- /dev/null +++ b/package-lock.json @@ -0,0 +1,1942 @@ +{ + "name": "joomla-weblinks", + "version": "4.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "joomla-weblinks", + "version": "4.0.0", + "license": "GPL-2.0-or-later", + "devDependencies": { + "cypress": "^12.7.0", + "joomla-cypress": "^0.0.16" + }, + "engines": { + "node": ">=16", + "npm": ">=8.5.5" + } + }, + "node_modules/@colors/colors": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.5.0.tgz", + "integrity": "sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==", + "dev": true, + "optional": true, + "engines": { + "node": ">=0.1.90" + } + }, + "node_modules/@cypress/request": { + "version": "2.88.11", + "resolved": "https://registry.npmjs.org/@cypress/request/-/request-2.88.11.tgz", + "integrity": "sha512-M83/wfQ1EkspjkE2lNWNV5ui2Cv7UCv1swW1DqljahbzLVWltcsexQh8jYtuS/vzFXP+HySntGM83ZXA9fn17w==", + "dev": true, + "dependencies": { + "aws-sign2": "~0.7.0", + "aws4": "^1.8.0", + "caseless": "~0.12.0", + "combined-stream": "~1.0.6", + "extend": "~3.0.2", + "forever-agent": "~0.6.1", + "form-data": "~2.3.2", + "http-signature": "~1.3.6", + "is-typedarray": "~1.0.0", + "isstream": "~0.1.2", + "json-stringify-safe": "~5.0.1", + "mime-types": "~2.1.19", + "performance-now": "^2.1.0", + "qs": "~6.10.3", + "safe-buffer": "^5.1.2", + "tough-cookie": "~2.5.0", + "tunnel-agent": "^0.6.0", + "uuid": "^8.3.2" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/@cypress/xvfb": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@cypress/xvfb/-/xvfb-1.2.4.tgz", + "integrity": "sha512-skbBzPggOVYCbnGgV+0dmBdW/s77ZkAOXIC1knS8NagwDjBrNC1LuXtQJeiN6l+m7lzmHtaoUw/ctJKdqkG57Q==", + "dev": true, + "dependencies": { + "debug": "^3.1.0", + "lodash.once": "^4.1.1" + } + }, + "node_modules/@cypress/xvfb/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/@types/node": { + "version": "14.18.47", + "resolved": "https://registry.npmjs.org/@types/node/-/node-14.18.47.tgz", + "integrity": "sha512-OuJi8bIng4wYHHA3YpKauL58dZrPxro3d0tabPHyiNF8rKfGKuVfr83oFlPLmKri1cX+Z3cJP39GXmnqkP11Gw==", + "dev": true + }, + "node_modules/@types/sinonjs__fake-timers": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/@types/sinonjs__fake-timers/-/sinonjs__fake-timers-8.1.1.tgz", + "integrity": "sha512-0kSuKjAS0TrGLJ0M/+8MaFkGsQhZpB6pxOmvS3K8FYI72K//YmdfoW9X2qPsAKh1mkwxGD5zib9s1FIFed6E8g==", + "dev": true + }, + "node_modules/@types/sizzle": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/@types/sizzle/-/sizzle-2.3.3.tgz", + "integrity": "sha512-JYM8x9EGF163bEyhdJBpR2QX1R5naCJHC8ucJylJ3w9/CVBaskdQ8WqBf8MmQrd1kRvp/a4TS8HJ+bxzR7ZJYQ==", + "dev": true + }, + "node_modules/@types/yauzl": { + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.10.0.tgz", + "integrity": "sha512-Cn6WYCm0tXv8p6k+A8PvbDG763EDpBoTzHdA+Q/MF6H3sapGjCm9NzoaJncJS9tUKSuCoDs9XHxYYsQDgxR6kw==", + "dev": true, + "optional": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/aggregate-error": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", + "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", + "dev": true, + "dependencies": { + "clean-stack": "^2.0.0", + "indent-string": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-colors": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz", + "integrity": "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/ansi-escapes": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", + "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", + "dev": true, + "dependencies": { + "type-fest": "^0.21.3" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/arch": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/arch/-/arch-2.2.0.tgz", + "integrity": "sha512-Of/R0wqp83cgHozfIYLbBMnej79U/SVGOOyuB3VVFv1NRM/PSFMK12x9KVtiYzJqmnU5WR2qp0Z5rHb7sWGnFQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/asn1": { + "version": "0.2.6", + "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.6.tgz", + "integrity": "sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==", + "dev": true, + "dependencies": { + "safer-buffer": "~2.1.0" + } + }, + "node_modules/assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw==", + "dev": true, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/astral-regex": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", + "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/async": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.4.tgz", + "integrity": "sha512-iAB+JbDEGXhyIUavoDl9WP/Jj106Kz9DEn1DPgYw5ruDn0e3Wgi3sKFm55sASdGBNOQB8F59d9qQ7deqrHA8wQ==", + "dev": true + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "dev": true + }, + "node_modules/at-least-node": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz", + "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==", + "dev": true, + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/aws-sign2": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", + "integrity": "sha512-08kcGqnYf/YmjoRhfxyu+CLxBjUtHLXLXX/vUfx9l2LYzG3c1m61nrpyFUZI6zeS+Li/wWMMidD9KgrqtGq3mA==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/aws4": { + "version": "1.12.0", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.12.0.tgz", + "integrity": "sha512-NmWvPnx0F1SfrQbYwOi7OeaNGokp9XhzNioJ/CSBs8Qa4vxug81mhJEAVZwxXuBmYB5KDRfMq/F3RR0BIU7sWg==", + "dev": true + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true + }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/bcrypt-pbkdf": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", + "integrity": "sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w==", + "dev": true, + "dependencies": { + "tweetnacl": "^0.14.3" + } + }, + "node_modules/blob-util": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/blob-util/-/blob-util-2.0.2.tgz", + "integrity": "sha512-T7JQa+zsXXEa6/8ZhHcQEW1UFfVM49Ts65uBkFL6fz2QmrElqmbajIDJvuA0tEhRe5eIjpV9ZF+0RfZR9voJFQ==", + "dev": true + }, + "node_modules/bluebird": { + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", + "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==", + "dev": true + }, + "node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, + "node_modules/buffer-crc32": { + "version": "0.2.13", + "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", + "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/cachedir": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/cachedir/-/cachedir-2.3.0.tgz", + "integrity": "sha512-A+Fezp4zxnit6FanDmv9EqXNAi3vt9DWp51/71UEhXukb7QUuvtv9344h91dyAxuTLoSYJFU299qzR3tzwPAhw==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/call-bind": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", + "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.1", + "get-intrinsic": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/caseless": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", + "integrity": "sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw==", + "dev": true + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/chalk/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/check-more-types": { + "version": "2.24.0", + "resolved": "https://registry.npmjs.org/check-more-types/-/check-more-types-2.24.0.tgz", + "integrity": "sha512-Pj779qHxV2tuapviy1bSZNEL1maXr13bPYpsvSDB68HlYcYuhlDrmGd63i0JHMCLKzc7rUSNIrpdJlhVlNwrxA==", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/ci-info": { + "version": "3.8.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.8.0.tgz", + "integrity": "sha512-eXTggHWSooYhq49F2opQhuHWgzucfF2YgODK4e1566GQs5BIfP30B0oenwBJHfWxAs2fyPB1s7Mg949zLf61Yw==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], + "engines": { + "node": ">=8" + } + }, + "node_modules/clean-stack": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", + "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/cli-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", + "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", + "dev": true, + "dependencies": { + "restore-cursor": "^3.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cli-table3": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/cli-table3/-/cli-table3-0.6.3.tgz", + "integrity": "sha512-w5Jac5SykAeZJKntOxJCrm63Eg5/4dhMWIcuTbo9rpE+brgaSZo0RuNJZeOyMgsUdhDeojvgyQLmjI+K50ZGyg==", + "dev": true, + "dependencies": { + "string-width": "^4.2.0" + }, + "engines": { + "node": "10.* || >= 12.*" + }, + "optionalDependencies": { + "@colors/colors": "1.5.0" + } + }, + "node_modules/cli-truncate": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-2.1.0.tgz", + "integrity": "sha512-n8fOixwDD6b/ObinzTrp1ZKFzbgvKZvuz/TvejnLn1aQfC6r52XEx85FmuC+3HI+JM7coBRXUvNqEU2PHVrHpg==", + "dev": true, + "dependencies": { + "slice-ansi": "^3.0.0", + "string-width": "^4.2.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/colorette": { + "version": "2.0.20", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz", + "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==", + "dev": true + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dev": true, + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/commander": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-6.2.1.tgz", + "integrity": "sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA==", + "dev": true, + "engines": { + "node": ">= 6" + } + }, + "node_modules/common-tags": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/common-tags/-/common-tags-1.8.2.tgz", + "integrity": "sha512-gk/Z852D2Wtb//0I+kRFNKKE9dIIVirjoqPoA1wJU+XePVXZfGeBpk45+A1rKO4Q43prqWBNY/MiIeRLbPWUaA==", + "dev": true, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true + }, + "node_modules/core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==", + "dev": true + }, + "node_modules/cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/cypress": { + "version": "12.12.0", + "resolved": "https://registry.npmjs.org/cypress/-/cypress-12.12.0.tgz", + "integrity": "sha512-UU5wFQ7SMVCR/hyKok/KmzG6fpZgBHHfrXcHzDmPHWrT+UUetxFzQgt7cxCszlwfozckzwkd22dxMwl/vNkWRw==", + "dev": true, + "hasInstallScript": true, + "dependencies": { + "@cypress/request": "^2.88.10", + "@cypress/xvfb": "^1.2.4", + "@types/node": "^14.14.31", + "@types/sinonjs__fake-timers": "8.1.1", + "@types/sizzle": "^2.3.2", + "arch": "^2.2.0", + "blob-util": "^2.0.2", + "bluebird": "^3.7.2", + "buffer": "^5.6.0", + "cachedir": "^2.3.0", + "chalk": "^4.1.0", + "check-more-types": "^2.24.0", + "cli-cursor": "^3.1.0", + "cli-table3": "~0.6.1", + "commander": "^6.2.1", + "common-tags": "^1.8.0", + "dayjs": "^1.10.4", + "debug": "^4.3.4", + "enquirer": "^2.3.6", + "eventemitter2": "6.4.7", + "execa": "4.1.0", + "executable": "^4.1.1", + "extract-zip": "2.0.1", + "figures": "^3.2.0", + "fs-extra": "^9.1.0", + "getos": "^3.2.1", + "is-ci": "^3.0.0", + "is-installed-globally": "~0.4.0", + "lazy-ass": "^1.6.0", + "listr2": "^3.8.3", + "lodash": "^4.17.21", + "log-symbols": "^4.0.0", + "minimist": "^1.2.8", + "ospath": "^1.2.2", + "pretty-bytes": "^5.6.0", + "proxy-from-env": "1.0.0", + "request-progress": "^3.0.0", + "semver": "^7.3.2", + "supports-color": "^8.1.1", + "tmp": "~0.2.1", + "untildify": "^4.0.0", + "yauzl": "^2.10.0" + }, + "bin": { + "cypress": "bin/cypress" + }, + "engines": { + "node": "^14.0.0 || ^16.0.0 || >=18.0.0" + } + }, + "node_modules/dashdash": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", + "integrity": "sha512-jRFi8UDGo6j+odZiEpjazZaWqEal3w/basFjQHQEwVtZJGDpxbH1MeYluwCS8Xq5wmLJooDlMgvVarmWfGM44g==", + "dev": true, + "dependencies": { + "assert-plus": "^1.0.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/dayjs": { + "version": "1.11.7", + "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.7.tgz", + "integrity": "sha512-+Yw9U6YO5TQohxLcIkrXBeY73WP3ejHWVvx8XCk3gxvQDCTEmS48ZrSZCKciI7Bhl/uCMyxYtE9UqRILmFphkQ==", + "dev": true + }, + "node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/ecc-jsbn": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", + "integrity": "sha512-eh9O+hwRHNbG4BLTjEl3nw044CkGm5X6LoaCf7LPp7UU8Qrt47JYNi6nPX8xjW97TKGKm1ouctg0QSpZe9qrnw==", + "dev": true, + "dependencies": { + "jsbn": "~0.1.0", + "safer-buffer": "^2.1.0" + } + }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "node_modules/end-of-stream": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "dev": true, + "dependencies": { + "once": "^1.4.0" + } + }, + "node_modules/enquirer": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.3.6.tgz", + "integrity": "sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==", + "dev": true, + "dependencies": { + "ansi-colors": "^4.1.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/eventemitter2": { + "version": "6.4.7", + "resolved": "https://registry.npmjs.org/eventemitter2/-/eventemitter2-6.4.7.tgz", + "integrity": "sha512-tYUSVOGeQPKt/eC1ABfhHy5Xd96N3oIijJvN3O9+TsC28T5V9yX9oEfEK5faP0EFSNVOG97qtAS68GBrQB2hDg==", + "dev": true + }, + "node_modules/execa": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-4.1.0.tgz", + "integrity": "sha512-j5W0//W7f8UxAn8hXVnwG8tLwdiUy4FJLcSupCg6maBYZDpyBvTApK7KyuI4bKj8KOh1r2YH+6ucuYtJv1bTZA==", + "dev": true, + "dependencies": { + "cross-spawn": "^7.0.0", + "get-stream": "^5.0.0", + "human-signals": "^1.1.1", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.0", + "onetime": "^5.1.0", + "signal-exit": "^3.0.2", + "strip-final-newline": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/executable": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/executable/-/executable-4.1.1.tgz", + "integrity": "sha512-8iA79xD3uAch729dUG8xaaBBFGaEa0wdD2VkYLFHwlqosEj/jT66AzcreRDSgV7ehnNLBW2WR5jIXwGKjVdTLg==", + "dev": true, + "dependencies": { + "pify": "^2.2.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", + "dev": true + }, + "node_modules/extract-zip": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-2.0.1.tgz", + "integrity": "sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg==", + "dev": true, + "dependencies": { + "debug": "^4.1.1", + "get-stream": "^5.1.0", + "yauzl": "^2.10.0" + }, + "bin": { + "extract-zip": "cli.js" + }, + "engines": { + "node": ">= 10.17.0" + }, + "optionalDependencies": { + "@types/yauzl": "^2.9.1" + } + }, + "node_modules/extsprintf": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", + "integrity": "sha512-11Ndz7Nv+mvAC1j0ktTa7fAb0vLyGGX+rMHNBYQviQDGU0Hw7lhctJANqbPhu9nV9/izT/IntTgZ7Im/9LJs9g==", + "dev": true, + "engines": [ + "node >=0.6.0" + ] + }, + "node_modules/fd-slicer": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", + "integrity": "sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==", + "dev": true, + "dependencies": { + "pend": "~1.2.0" + } + }, + "node_modules/figures": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", + "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==", + "dev": true, + "dependencies": { + "escape-string-regexp": "^1.0.5" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/forever-agent": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", + "integrity": "sha512-j0KLYPhm6zeac4lz3oJ3o65qvgQCcPubiyotZrXqEaG4hNagNYO8qdlUrX5vwqv9ohqeT/Z3j6+yW067yWWdUw==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/form-data": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", + "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", + "dev": true, + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.6", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 0.12" + } + }, + "node_modules/fs-extra": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", + "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "dev": true, + "dependencies": { + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true + }, + "node_modules/function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "dev": true + }, + "node_modules/get-intrinsic": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.1.tgz", + "integrity": "sha512-2DcsyfABl+gVHEfCOaTrWgyt+tb6MSEGmKq+kI5HwLbIYgjgmMcV8KQ41uaKz1xxUcn9tJtgFbQUEVcEbd0FYw==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-stream": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", + "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", + "dev": true, + "dependencies": { + "pump": "^3.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/getos": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/getos/-/getos-3.2.1.tgz", + "integrity": "sha512-U56CfOK17OKgTVqozZjUKNdkfEv6jk5WISBJ8SHoagjE6L69zOwl3Z+O8myjY9MEW3i2HPWQBt/LTbCgcC973Q==", + "dev": true, + "dependencies": { + "async": "^3.2.0" + } + }, + "node_modules/getpass": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", + "integrity": "sha512-0fzj9JxOLfJ+XGLhR8ze3unN0KZCgZwiSSDz168VERjK8Wl8kVSdcu2kspd4s4wtAa1y/qrVRiAA0WclVsu0ng==", + "dev": true, + "dependencies": { + "assert-plus": "^1.0.0" + } + }, + "node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/global-dirs": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/global-dirs/-/global-dirs-3.0.1.tgz", + "integrity": "sha512-NBcGGFbBA9s1VzD41QXDG+3++t9Mn5t1FpLdhESY6oKY4gYTFpX4wO3sqGUa0Srjtbfj3szX0RnemmrVRUdULA==", + "dev": true, + "dependencies": { + "ini": "2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "dev": true + }, + "node_modules/has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.1" + }, + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/has-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.1.tgz", + "integrity": "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/http-signature": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.3.6.tgz", + "integrity": "sha512-3adrsD6zqo4GsTqtO7FyrejHNv+NgiIfAfv68+jVlFmSr9OGy7zrxONceFRLKvnnZA5jbxQBX1u9PpB6Wi32Gw==", + "dev": true, + "dependencies": { + "assert-plus": "^1.0.0", + "jsprim": "^2.0.2", + "sshpk": "^1.14.1" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/human-signals": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-1.1.1.tgz", + "integrity": "sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw==", + "dev": true, + "engines": { + "node": ">=8.12.0" + } + }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/indent-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", + "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "dev": true, + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + }, + "node_modules/ini": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ini/-/ini-2.0.0.tgz", + "integrity": "sha512-7PnF4oN3CvZF23ADhA5wRaYEQpJ8qygSkbtTXWBeXWXmEVRXK+1ITciHWwHhsjv1TmW0MgacIv6hEi5pX5NQdA==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/is-ci": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-3.0.1.tgz", + "integrity": "sha512-ZYvCgrefwqoQ6yTyYUbQu64HsITZ3NfKX1lzaEYdkTDcfKzzCI/wthRRYKkdjHKFVgNiXKAKm65Zo1pk2as/QQ==", + "dev": true, + "dependencies": { + "ci-info": "^3.2.0" + }, + "bin": { + "is-ci": "bin.js" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-installed-globally": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/is-installed-globally/-/is-installed-globally-0.4.0.tgz", + "integrity": "sha512-iwGqO3J21aaSkC7jWnHP/difazwS7SFeIqxv6wEtLU8Y5KlzFTjyqcSIT0d8s4+dDhKytsk9PJZ2BkS5eZwQRQ==", + "dev": true, + "dependencies": { + "global-dirs": "^3.0.0", + "is-path-inside": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-path-inside": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==", + "dev": true + }, + "node_modules/is-unicode-supported": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", + "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true + }, + "node_modules/isstream": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", + "integrity": "sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g==", + "dev": true + }, + "node_modules/joomla-cypress": { + "version": "0.0.16", + "resolved": "https://registry.npmjs.org/joomla-cypress/-/joomla-cypress-0.0.16.tgz", + "integrity": "sha512-Ku+ykwChSklRmmIhRMeGmVk4vLCUG2TWAAUseFMo8Yg0cD1jB9csK4pTiwwOBhx7TvT3Sps/RFk68eh3y/cTJw==", + "dev": true + }, + "node_modules/jsbn": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", + "integrity": "sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg==", + "dev": true + }, + "node_modules/json-schema": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz", + "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==", + "dev": true + }, + "node_modules/json-stringify-safe": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", + "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==", + "dev": true + }, + "node_modules/jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "dev": true, + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/jsprim": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-2.0.2.tgz", + "integrity": "sha512-gqXddjPqQ6G40VdnI6T6yObEC+pDNvyP95wdQhkWkg7crHH3km5qP1FsOXEkzEQwnz6gz5qGTn1c2Y52wP3OyQ==", + "dev": true, + "engines": [ + "node >=0.6.0" + ], + "dependencies": { + "assert-plus": "1.0.0", + "extsprintf": "1.3.0", + "json-schema": "0.4.0", + "verror": "1.10.0" + } + }, + "node_modules/lazy-ass": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/lazy-ass/-/lazy-ass-1.6.0.tgz", + "integrity": "sha512-cc8oEVoctTvsFZ/Oje/kGnHbpWHYBe8IAJe4C0QNc3t8uM/0Y8+erSz/7Y1ALuXTEZTMvxXwO6YbX1ey3ujiZw==", + "dev": true, + "engines": { + "node": "> 0.8" + } + }, + "node_modules/listr2": { + "version": "3.14.0", + "resolved": "https://registry.npmjs.org/listr2/-/listr2-3.14.0.tgz", + "integrity": "sha512-TyWI8G99GX9GjE54cJ+RrNMcIFBfwMPxc3XTFiAYGN4s10hWROGtOg7+O6u6LE3mNkyld7RSLE6nrKBvTfcs3g==", + "dev": true, + "dependencies": { + "cli-truncate": "^2.1.0", + "colorette": "^2.0.16", + "log-update": "^4.0.0", + "p-map": "^4.0.0", + "rfdc": "^1.3.0", + "rxjs": "^7.5.1", + "through": "^2.3.8", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "enquirer": ">= 2.3.0 < 3" + }, + "peerDependenciesMeta": { + "enquirer": { + "optional": true + } + } + }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "dev": true + }, + "node_modules/lodash.once": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", + "integrity": "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==", + "dev": true + }, + "node_modules/log-symbols": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", + "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", + "dev": true, + "dependencies": { + "chalk": "^4.1.0", + "is-unicode-supported": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/log-update": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/log-update/-/log-update-4.0.0.tgz", + "integrity": "sha512-9fkkDevMefjg0mmzWFBW8YkFP91OrizzkW3diF7CpG+S2EYdy4+TVfGwz1zeF8x7hCx1ovSPTOE9Ngib74qqUg==", + "dev": true, + "dependencies": { + "ansi-escapes": "^4.3.0", + "cli-cursor": "^3.1.0", + "slice-ansi": "^4.0.0", + "wrap-ansi": "^6.2.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/log-update/node_modules/slice-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", + "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "astral-regex": "^2.0.0", + "is-fullwidth-code-point": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/slice-ansi?sponsor=1" + } + }, + "node_modules/log-update/node_modules/wrap-ansi": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", + "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dev": true, + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/npm-run-path": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "dev": true, + "dependencies": { + "path-key": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/object-inspect": { + "version": "1.12.3", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.3.tgz", + "integrity": "sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "dev": true, + "dependencies": { + "mimic-fn": "^2.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ospath": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/ospath/-/ospath-1.2.2.tgz", + "integrity": "sha512-o6E5qJV5zkAbIDNhGSIlyOhScKXgQrSRMilfph0clDfM0nEnBOlKlH4sWDmG95BW/CvwNz0vmm7dJVtU2KlMiA==", + "dev": true + }, + "node_modules/p-map": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz", + "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", + "dev": true, + "dependencies": { + "aggregate-error": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/pend": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", + "integrity": "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==", + "dev": true + }, + "node_modules/performance-now": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", + "integrity": "sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==", + "dev": true + }, + "node_modules/pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/pretty-bytes": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-5.6.0.tgz", + "integrity": "sha512-FFw039TmrBqFK8ma/7OL3sDz/VytdtJr044/QUJtH0wK9lb9jLq9tJyIxUwtQJHwar2BqtiA4iCWSwo9JLkzFg==", + "dev": true, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/proxy-from-env": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.0.0.tgz", + "integrity": "sha512-F2JHgJQ1iqwnHDcQjVBsq3n/uoaFL+iPW/eAeL7kVxy/2RrWaN4WroKjjvbsoRtv0ftelNyC01bjRhn/bhcf4A==", + "dev": true + }, + "node_modules/psl": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz", + "integrity": "sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==", + "dev": true + }, + "node_modules/pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "dev": true, + "dependencies": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "node_modules/punycode": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz", + "integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/qs": { + "version": "6.10.4", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.10.4.tgz", + "integrity": "sha512-OQiU+C+Ds5qiH91qh/mg0w+8nwQuLjM4F4M/PbmhDOoYehPh+Fb0bDjtR1sOvy7YKxvj28Y/M0PhP5uVX0kB+g==", + "dev": true, + "dependencies": { + "side-channel": "^1.0.4" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/request-progress": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/request-progress/-/request-progress-3.0.0.tgz", + "integrity": "sha512-MnWzEHHaxHO2iWiQuHrUPBi/1WeBf5PkxQqNyNvLl9VAYSdXkP8tQ3pBSeCPD+yw0v0Aq1zosWLz0BdeXpWwZg==", + "dev": true, + "dependencies": { + "throttleit": "^1.0.0" + } + }, + "node_modules/restore-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", + "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", + "dev": true, + "dependencies": { + "onetime": "^5.1.0", + "signal-exit": "^3.0.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/rfdc": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.3.0.tgz", + "integrity": "sha512-V2hovdzFbOi77/WajaSMXk2OLm+xNIeQdMMuB7icj7bk6zi2F8GGAxigcnDFpJHbNyNcgyJDiP+8nOrY5cZGrA==", + "dev": true + }, + "node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/rxjs": { + "version": "7.8.1", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", + "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==", + "dev": true, + "dependencies": { + "tslib": "^2.1.0" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "dev": true + }, + "node_modules/semver": { + "version": "7.5.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.1.tgz", + "integrity": "sha512-Wvss5ivl8TMRZXXESstBA4uR5iXgEN/VC5/sOcuXdVLzcdkz4HWetIoRfG5gb5X+ij/G9rw9YoGn3QoQ8OCSpw==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/side-channel": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", + "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.0", + "get-intrinsic": "^1.0.2", + "object-inspect": "^1.9.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true + }, + "node_modules/slice-ansi": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-3.0.0.tgz", + "integrity": "sha512-pSyv7bSTC7ig9Dcgbw9AuRNUb5k5V6oDudjZoMBSr13qpLBG7tB+zgCkARjq7xIUgdz5P1Qe8u+rSGdouOOIyQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "astral-regex": "^2.0.0", + "is-fullwidth-code-point": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/sshpk": { + "version": "1.17.0", + "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.17.0.tgz", + "integrity": "sha512-/9HIEs1ZXGhSPE8X6Ccm7Nam1z8KcoCqPdI7ecm1N33EzAetWahvQWVqLZtaZQ+IDKX4IyA2o0gBzqIMkAagHQ==", + "dev": true, + "dependencies": { + "asn1": "~0.2.3", + "assert-plus": "^1.0.0", + "bcrypt-pbkdf": "^1.0.0", + "dashdash": "^1.12.0", + "ecc-jsbn": "~0.1.1", + "getpass": "^0.1.1", + "jsbn": "~0.1.0", + "safer-buffer": "^2.0.2", + "tweetnacl": "~0.14.0" + }, + "bin": { + "sshpk-conv": "bin/sshpk-conv", + "sshpk-sign": "bin/sshpk-sign", + "sshpk-verify": "bin/sshpk-verify" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-final-newline": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", + "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/throttleit": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/throttleit/-/throttleit-1.0.0.tgz", + "integrity": "sha512-rkTVqu6IjfQ/6+uNuuc3sZek4CEYxTJom3IktzgdSxcZqdARuebbA/f4QmAxMQIxqq9ZLEUkSYqvuk1I6VKq4g==", + "dev": true + }, + "node_modules/through": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==", + "dev": true + }, + "node_modules/tmp": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.1.tgz", + "integrity": "sha512-76SUhtfqR2Ijn+xllcI5P1oyannHNHByD80W1q447gU3mp9G9PSpGdWmjUOHRDPiHYacIk66W7ubDTuPF3BEtQ==", + "dev": true, + "dependencies": { + "rimraf": "^3.0.0" + }, + "engines": { + "node": ">=8.17.0" + } + }, + "node_modules/tough-cookie": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", + "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", + "dev": true, + "dependencies": { + "psl": "^1.1.28", + "punycode": "^2.1.1" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/tslib": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", + "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", + "dev": true + }, + "node_modules/tunnel-agent": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==", + "dev": true, + "dependencies": { + "safe-buffer": "^5.0.1" + }, + "engines": { + "node": "*" + } + }, + "node_modules/tweetnacl": { + "version": "0.14.5", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", + "integrity": "sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA==", + "dev": true + }, + "node_modules/type-fest": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", + "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/universalify": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", + "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", + "dev": true, + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/untildify": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/untildify/-/untildify-4.0.0.tgz", + "integrity": "sha512-KK8xQ1mkzZeg9inewmFVDNkg3l5LUhoq9kN6iWYB/CC9YMG8HA+c1Q8HwDe6dEX7kErrEVNVBO3fWsVq5iDgtw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "dev": true, + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/verror": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", + "integrity": "sha512-ZZKSmDAEFOijERBLkmYfJ+vmk3w+7hOLYDNkRCuRuMJGEmqYNCNLyBBFwWKVMhfwaEF3WOd0Zlw86U/WC/+nYw==", + "dev": true, + "engines": [ + "node >=0.6.0" + ], + "dependencies": { + "assert-plus": "^1.0.0", + "core-util-is": "1.0.2", + "extsprintf": "^1.2.0" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true + }, + "node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "node_modules/yauzl": { + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", + "integrity": "sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==", + "dev": true, + "dependencies": { + "buffer-crc32": "~0.2.3", + "fd-slicer": "~1.1.0" + } + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..72dca7b --- /dev/null +++ b/package.json @@ -0,0 +1,25 @@ +{ + "name": "joomla-weblinks", + "version": "4.0.0", + "description": "Weblinks extension", + "license": "GPL-2.0-or-later", + "repository": { + "type": "git", + "url": "https://github.com/joomla-extensions/weblinks.git" + }, + "engines": { + "node": ">=16", + "npm": ">=8.5.5" + }, + "scripts": { + "cypress:install": "cypress install", + "cypress:open": "cypress open", + "cypress:run": "cypress run" + }, + "dependencies": { + }, + "devDependencies": { + "cypress": "^12.7.0", + "joomla-cypress": "^0.0.16" + } +} diff --git a/phpstan.neon b/phpstan.neon new file mode 100644 index 0000000..5a27c34 --- /dev/null +++ b/phpstan.neon @@ -0,0 +1,11 @@ +includes: + - vendor/phpstan/phpstan-deprecation-rules/rules.neon +parameters: + level: 6 + paths: + - src + scanDirectories: + - joomla/libraries + - joomla/administrator/components/com_finder/src/Indexer + ignoreErrors: + reportUnmatchedIgnoredErrors: false diff --git a/ruleset.xml b/ruleset.xml new file mode 100644 index 0000000..7d69c2c --- /dev/null +++ b/ruleset.xml @@ -0,0 +1,48 @@ + + + The Joomla CMS PSR-12 exceptions. + + + + + src/administrator/components/com_weblinks/layouts/* + + + + + + + + + + + + + src/administrator/components/com_weblinks/script\.php + src/administrator/manifests/packages/weblinks/script\.php + src/administrator/components/com_weblinks/helpers/weblinks\.php + src/components/com_weblinks/helpers/icon\.php + src/components/com_weblinks/helpers/route\.php + + + + src/components/com_weblinks/src/Model/CategoriesModel\.php + src/components/com_weblinks/src/Model/CategoryModel\.php + src/components/com_weblinks/src/Model/WeblinkModel\.php + src/administrator/components/com_weblinks/src/Table/*\.php + + + + src/administrator/components/com_weblinks/script\.php + src/administrator/manifests/packages/weblinks/script\.php + + + + src/administrator/components/com_weblinks/src/Table/*\.php + + + + src/administrator/components/com_weblinks/script\.php + src/administrator/manifests/packages/weblinks/script\.php + + diff --git a/src/administrator/components/com_weblinks/helpers/weblinks.php b/src/administrator/components/com_weblinks/helpers/weblinks.php index 8e19ede..46baefc 100644 --- a/src/administrator/components/com_weblinks/helpers/weblinks.php +++ b/src/administrator/components/com_weblinks/helpers/weblinks.php @@ -1,4 +1,5 @@ load(array('extension' => 'com_weblinks', 'title' => 'Uncategorised'))) - { - $category->extension = 'com_weblinks'; - $category->title = 'Uncategorised'; - $category->description = ''; - $category->published = 1; - $category->access = 1; - $category->params = '{"category_layout":"","image":""}'; - $category->metadata = '{"author":"","robots":""}'; - $category->metadesc = ''; - $category->metakey = ''; - $category->language = '*'; - $category->checked_out_time = null; - $category->version = 1; - $category->hits = 0; - $category->modified_user_id = 0; - $category->checked_out = null; + // Check if the Uncategorised category exists before adding it + if (!$category->load(['extension' => 'com_weblinks', 'title' => 'Uncategorised'])) { + $category->extension = 'com_weblinks'; + $category->title = 'Uncategorised'; + $category->description = ''; + $category->published = 1; + $category->access = 1; + $category->params = '{"category_layout":"","image":""}'; + $category->metadata = '{"author":"","robots":""}'; + $category->metadesc = ''; + $category->metakey = ''; + $category->language = '*'; + $category->checked_out_time = null; + $category->version = 1; + $category->hits = 0; + $category->modified_user_id = 0; + $category->checked_out = null; - // Set the location in the tree - $category->setLocation(1, 'last-child'); + // Set the location in the tree + $category->setLocation(1, 'last-child'); - // Check to make sure our data is valid - if (!$category->check()) - { - Factory::getApplication()->enqueueMessage(Text::sprintf('COM_WEBLINKS_ERROR_INSTALL_CATEGORY', $category->getError())); + // Check to make sure our data is valid + if (!$category->check()) { + Factory::getApplication()->enqueueMessage(Text::sprintf('COM_WEBLINKS_ERROR_INSTALL_CATEGORY', $category->getError())); - return; - } + return; + } - // Now store the category - if (!$category->store(true)) - { - Factory::getApplication()->enqueueMessage(Text::sprintf('COM_WEBLINKS_ERROR_INSTALL_CATEGORY', $category->getError())); + // Now store the category + if (!$category->store(true)) { + Factory::getApplication()->enqueueMessage(Text::sprintf('COM_WEBLINKS_ERROR_INSTALL_CATEGORY', $category->getError())); - return; - } + return; + } - // Build the path for our category - $category->rebuildPath($category->id); - } - } + // Build the path for our category + $category->rebuildPath($category->id); + } + } - /** - * Method to run after the install routine. - * - * @param string $type The action being performed - * @param JInstallerAdapterComponent $parent The class calling this method - * - * @return void - * - * @since 3.4.1 - */ - public function postflight($type, $parent) - { - // Only execute database changes on MySQL databases - $dbName = Factory::getDbo()->name; + /** + * Method to run after the install routine. + * + * @param string $type The action being performed + * @param JInstallerAdapterComponent $parent The class calling this method + * + * @return void + * + * @since 3.4.1 + */ + public function postflight($type, $parent) + { + // Only execute database changes on MySQL databases + $dbName = Factory::getDbo()->name; - if (strpos($dbName, 'mysql') !== false) - { - // Add Missing Table Columns if needed - $this->addColumnsIfNeeded(); + if (strpos($dbName, 'mysql') !== false) { + // Add Missing Table Columns if needed + $this->addColumnsIfNeeded(); - // Drop the Table Columns if needed - $this->dropColumnsIfNeeded(); - } + // Drop the Table Columns if needed + $this->dropColumnsIfNeeded(); + } - // Insert missing UCM Records if needed - $this->insertMissingUcmRecords(); - } + // Insert missing UCM Records if needed + $this->insertMissingUcmRecords(); + } - /** - * Method to insert missing records for the UCM tables - * - * @return void - * - * @since 3.4.1 - */ - private function insertMissingUcmRecords() - { - // Insert the rows in the #__content_types table if they don't exist already - $db = Factory::getDbo(); + /** + * Method to insert missing records for the UCM tables + * + * @return void + * + * @since 3.4.1 + */ + private function insertMissingUcmRecords() + { + // Insert the rows in the #__content_types table if they don't exist already + $db = Factory::getDbo(); - // Get the type ID for a Weblink - $query = $db->getQuery(true); - $query->select($db->quoteName('type_id')) - ->from($db->quoteName('#__content_types')) - ->where($db->quoteName('type_alias') . ' = ' . $db->quote('com_weblinks.weblink')); - $db->setQuery($query); + // Get the type ID for a Weblink + $query = $db->getQuery(true); + $query->select($db->quoteName('type_id')) + ->from($db->quoteName('#__content_types')) + ->where($db->quoteName('type_alias') . ' = ' . $db->quote('com_weblinks.weblink')); + $db->setQuery($query); - $weblinkTypeId = $db->loadResult(); + $weblinkTypeId = $db->loadResult(); - // Get the type ID for a Weblink Category - $query->clear('where'); - $query->where($db->quoteName('type_alias') . ' = ' . $db->quote('com_weblinks.category')); - $db->setQuery($query); + // Get the type ID for a Weblink Category + $query->clear('where'); + $query->where($db->quoteName('type_alias') . ' = ' . $db->quote('com_weblinks.category')); + $db->setQuery($query); - $categoryTypeId = $db->loadResult(); + $categoryTypeId = $db->loadResult(); - // Set the table columns to insert table to - $columnsArray = array( - $db->quoteName('type_title'), - $db->quoteName('type_alias'), - $db->quoteName('table'), - $db->quoteName('rules'), - $db->quoteName('field_mappings'), - $db->quoteName('router'), - $db->quoteName('content_history_options'), - ); + // Set the table columns to insert table to + $columnsArray = [ + $db->quoteName('type_title'), + $db->quoteName('type_alias'), + $db->quoteName('table'), + $db->quoteName('rules'), + $db->quoteName('field_mappings'), + $db->quoteName('router'), + $db->quoteName('content_history_options'), + ]; - // If we have no type id for com_weblinks.weblink insert it - if (!$weblinkTypeId) - { - // Insert the data. - $query->clear(); - $query->insert($db->quoteName('#__content_types')); - $query->columns($columnsArray); - $query->values( - $db->quote('Weblink') . ', ' - . $db->quote('com_weblinks.weblink') . ', ' - . $db->quote( - '{"special":{"dbtable":"#__weblinks","key":"id","type":"Weblink","prefix":"WeblinksTable","config":"array()"}, + // If we have no type id for com_weblinks.weblink insert it + if (!$weblinkTypeId) { + // Insert the data. + $query->clear(); + $query->insert($db->quoteName('#__content_types')); + $query->columns($columnsArray); + $query->values( + $db->quote('Weblink') . ', ' + . $db->quote('com_weblinks.weblink') . ', ' + . $db->quote( + '{"special":{"dbtable":"#__weblinks","key":"id","type":"Weblink","prefix":"WeblinksTable","config":"array()"}, "common":{"dbtable":"#__ucm_content","key":"ucm_id","type":"Corecontent","prefix":"JTable","config":"array()"}}' - ) . ', ' - . $db->quote('') . ', ' - . $db->quote( - '{"common":{"core_content_item_id":"id","core_title":"title","core_state":"state","core_alias":"alias", + ) . ', ' + . $db->quote('') . ', ' + . $db->quote( + '{"common":{"core_content_item_id":"id","core_title":"title","core_state":"state","core_alias":"alias", "core_created_time":"created","core_modified_time":"modified","core_body":"description", "core_hits":"hits", "core_publish_up":"publish_up","core_publish_down":"publish_down","core_access":"access", "core_params":"params", "core_featured":"featured", "core_metadata":"metadata", "core_language":"language", "core_images":"images", "core_urls":"url", "core_version":"version", "core_ordering":"ordering", "core_metakey":"metakey", "core_metadesc":"metadesc", "core_catid":"catid", "core_xreference":"xreference", "asset_id":"null"}, "special":{}}' - ) . ', ' - . $db->quote('WeblinksHelperRoute::getWeblinkRoute') . ', ' - . $db->quote( - '{"formFile":"administrator\\/components\\/com_weblinks\\/models\\/forms\\/weblink.xml", + ) . ', ' + . $db->quote('WeblinksHelperRoute::getWeblinkRoute') . ', ' + . $db->quote( + '{"formFile":"administrator\\/components\\/com_weblinks\\/models\\/forms\\/weblink.xml", "hideFields":["asset_id","checked_out","checked_out_time","version","featured","images"], "ignoreChanges":["modified_by", "modified", "checked_out", "checked_out_time", "version", "hits"], "convertToInt":["publish_up", "publish_down", "featured", "ordering"], "displayLookup":[{"sourceColumn":"catid","targetTable":"#__categories","targetColumn":"id","displayColumn":"title"}, {"sourceColumn":"created_by","targetTable":"#__users","targetColumn":"id","displayColumn":"name"}, {"sourceColumn":"access","targetTable":"#__viewlevels","targetColumn":"id","displayColumn":"title"}, {"sourceColumn":"modified_by","targetTable":"#__users","targetColumn":"id","displayColumn":"name"} ]}' - ) - ); + ) + ); - $db->setQuery($query); - $db->execute(); - } + $db->setQuery($query); + $db->execute(); + } - // If we have no type id for com_weblinks.category insert it - if (!$categoryTypeId) - { - // Insert the data. - $query->clear(); - $query->insert($db->quoteName('#__content_types')); - $query->columns($columnsArray); - $query->values( - $db->quote('Weblinks Category') . ', ' - . $db->quote('com_weblinks.category') . ', ' - . $db->quote(' + // If we have no type id for com_weblinks.category insert it + if (!$categoryTypeId) { + // Insert the data. + $query->clear(); + $query->insert($db->quoteName('#__content_types')); + $query->columns($columnsArray); + $query->values( + $db->quote('Weblinks Category') . ', ' + . $db->quote('com_weblinks.category') . ', ' + . $db->quote(' {"special":{"dbtable":"#__categories","key":"id","type":"Category","prefix":"JTable","config":"array()"}, - "common":{"dbtable":"#__ucm_content","key":"ucm_id","type":"Corecontent","prefix":"JTable","config":"array()"}}' - ) . ', ' - . $db->quote('') . ', ' - . $db->quote(' + "common":{"dbtable":"#__ucm_content","key":"ucm_id","type":"Corecontent","prefix":"JTable","config":"array()"}}') . ', ' + . $db->quote('') . ', ' + . $db->quote(' {"common":{"core_content_item_id":"id","core_title":"title","core_state":"published","core_alias":"alias", "core_created_time":"created_time","core_modified_time":"modified_time","core_body":"description", "core_hits":"hits","core_publish_up":"null","core_publish_down":"null","core_access":"access", "core_params":"params", "core_featured":"null", "core_metadata":"metadata", "core_language":"language", "core_images":"null", "core_urls":"null", "core_version":"version", "core_ordering":"null", "core_metakey":"metakey", "core_metadesc":"metadesc", "core_catid":"parent_id", "core_xreference":"null", "asset_id":"asset_id"}, - "special":{"parent_id":"parent_id","lft":"lft","rgt":"rgt","level":"level","path":"path","extension":"extension","note":"note"}}' - ) . ', ' - . $db->quote('WeblinksHelperRoute::getCategoryRoute') . ', ' - . $db->quote(' + "special":{"parent_id":"parent_id","lft":"lft","rgt":"rgt","level":"level","path":"path","extension":"extension","note":"note"}}') . ', ' + . $db->quote('WeblinksHelperRoute::getCategoryRoute') . ', ' + . $db->quote(' {"formFile":"administrator\\/components\\/com_categories\\/models\\/forms\\/category.xml", "hideFields":["asset_id","checked_out","checked_out_time","version","lft","rgt","level","path","extension"], "ignoreChanges":["modified_user_id", "modified_time", "checked_out", "checked_out_time", "version", @@ -277,68 +268,64 @@ class Com_WeblinksInstallerScript "displayColumn":"name"},{"sourceColumn":"access","targetTable":"#__viewlevels","targetColumn":"id", "displayColumn":"title"},{"sourceColumn":"modified_user_id","targetTable":"#__users","targetColumn":"id", "displayColumn":"name"},{"sourceColumn":"parent_id","targetTable":"#__categories","targetColumn":"id", - "displayColumn":"title"}]}' - ) - ); + "displayColumn":"title"}]}') + ); - $db->setQuery($query); - $db->execute(); - } - } + $db->setQuery($query); + $db->execute(); + } + } - /** - * Method to drop colums from #__weblinks if they still there. - * - * @return void - * - * @since 3.4.1 - */ - private function dropColumnsIfNeeded() - { - $oldColumns = array( - 'sid', - 'date', - 'archived', - 'approved', - ); + /** + * Method to drop colums from #__weblinks if they still there. + * + * @return void + * + * @since 3.4.1 + */ + private function dropColumnsIfNeeded() + { + $oldColumns = [ + 'sid', + 'date', + 'archived', + 'approved', + ]; - $db = Factory::getDbo(); - $table = $db->getTableColumns('#__weblinks'); + $db = Factory::getDbo(); + $table = $db->getTableColumns('#__weblinks'); - $columns = array_intersect($oldColumns, array_keys($table)); + $columns = array_intersect($oldColumns, array_keys($table)); - foreach ($columns as $column) - { - $sql = 'ALTER TABLE ' . $db->quoteName('#__weblinks') . ' DROP COLUMN ' . $db->quoteName($column); - $db->setQuery($sql); - $db->execute(); - } - } + foreach ($columns as $column) { + $sql = 'ALTER TABLE ' . $db->quoteName('#__weblinks') . ' DROP COLUMN ' . $db->quoteName($column); + $db->setQuery($sql); + $db->execute(); + } + } - /** - * Method to add colums from #__weblinks if they are missing. - * - * @return void - * - * @since 3.4.1 - */ - private function addColumnsIfNeeded() - { - $db = Factory::getDbo(); - $table = $db->getTableColumns('#__weblinks'); + /** + * Method to add colums from #__weblinks if they are missing. + * + * @return void + * + * @since 3.4.1 + */ + private function addColumnsIfNeeded() + { + $db = Factory::getDbo(); + $table = $db->getTableColumns('#__weblinks'); - if (!array_key_exists('version', $table)) - { - $sql = 'ALTER TABLE ' . $db->quoteName('#__weblinks') . ' ADD COLUMN ' . $db->quoteName('version') . " int unsigned NOT NULL DEFAULT '1'"; - $db->setQuery($sql); - $db->execute(); - } + if (!array_key_exists('version', $table)) { + $sql = 'ALTER TABLE ' . $db->quoteName('#__weblinks') . ' ADD COLUMN ' . $db->quoteName('version') . " int unsigned NOT NULL DEFAULT '1'"; + $db->setQuery($sql); + $db->execute(); + } - if (!array_key_exists('images', $table)) - { - $sql = 'ALTER TABLE ' . $db->quoteName('#__weblinks') . ' ADD COLUMN ' . $db->quoteName('images') . ' text NOT NULL'; - $db->setQuery($sql); - $db->execute(); - } - } + if (!array_key_exists('images', $table)) { + $sql = 'ALTER TABLE ' . $db->quoteName('#__weblinks') . ' ADD COLUMN ' . $db->quoteName('images') . ' text NOT NULL'; + $db->setQuery($sql); + $db->execute(); + } + } } diff --git a/src/administrator/components/com_weblinks/services/provider.php b/src/administrator/components/com_weblinks/services/provider.php index a9470bd..b794e32 100644 --- a/src/administrator/components/com_weblinks/services/provider.php +++ b/src/administrator/components/com_weblinks/services/provider.php @@ -1,4 +1,5 @@ set(AssociationExtensionInterface::class, new AssociationsHelper); - - $componentNamespace = '\\Joomla\\Component\\Weblinks'; - - $container->registerServiceProvider(new CategoryFactory($componentNamespace)); - $container->registerServiceProvider(new MVCFactory($componentNamespace)); - $container->registerServiceProvider(new ComponentDispatcherFactory($componentNamespace)); - $container->registerServiceProvider(new RouterFactory($componentNamespace)); - - $container->set( - ComponentInterface::class, - function (Container $container) { - $component = new WeblinksComponent($container->get(ComponentDispatcherFactoryInterface::class)); - - $component->setRegistry($container->get(Registry::class)); - $component->setMVCFactory($container->get(MVCFactoryInterface::class)); - $component->setCategoryFactory($container->get(CategoryFactoryInterface::class)); - $component->setAssociationExtension($container->get(AssociationExtensionInterface::class)); - $component->setRouterFactory($container->get(RouterFactoryInterface::class)); - - return $component; - } - ); - } +return new class () implements ServiceProviderInterface { + /** + * Registers the service provider with a DI container. + * + * @param Container $container The DI container. + * + * @return void + * + * @since 4.0.0 + */ + public function register(Container $container) + { + $container->set(AssociationExtensionInterface::class, new AssociationsHelper()); + $componentNamespace = '\\Joomla\\Component\\Weblinks'; + $container->registerServiceProvider(new CategoryFactory($componentNamespace)); + $container->registerServiceProvider(new MVCFactory($componentNamespace)); + $container->registerServiceProvider(new ComponentDispatcherFactory($componentNamespace)); + $container->registerServiceProvider(new RouterFactory($componentNamespace)); + $container->set(ComponentInterface::class, function (Container $container) { + $component = new WeblinksComponent($container->get(ComponentDispatcherFactoryInterface::class)); + $component->setRegistry($container->get(Registry::class)); + $component->setMVCFactory($container->get(MVCFactoryInterface::class)); + $component->setCategoryFactory($container->get(CategoryFactoryInterface::class)); + $component->setAssociationExtension($container->get(AssociationExtensionInterface::class)); + $component->setRouterFactory($container->get(RouterFactoryInterface::class)); + return $component; + }); + } }; diff --git a/src/administrator/components/com_weblinks/src/Controller/DisplayController.php b/src/administrator/components/com_weblinks/src/Controller/DisplayController.php index 67fcf1f..813bab9 100644 --- a/src/administrator/components/com_weblinks/src/Controller/DisplayController.php +++ b/src/administrator/components/com_weblinks/src/Controller/DisplayController.php @@ -1,4 +1,5 @@ input->get('view', 'weblinks'); + $layout = $this->input->get('layout', 'default'); + $id = $this->input->getInt('id'); + // Check for edit form. + if ($view == 'weblink' && $layout == 'edit' && !$this->checkEditId('com_weblinks.edit.weblink', $id)) { + // Somehow the person just went to the form - we don't allow that. + if (!\count($this->app->getMessageQueue())) { + $this->setMessage(Text::sprintf('JLIB_APPLICATION_ERROR_UNHELD_ID', $id), 'error'); + } - /** - * Method to display a view. - * - * @param boolean $cacheable If true, the view output will be cached - * @param array $urlparams An array of safe url parameters and their variable types, - * for valid values see {@link JFilterInput::clean()}. - * - * @return BaseController|boolean This object to support chaining. - * - * @since 1.5 - */ - public function display($cacheable = false, $urlparams = false) - { - $view = $this->input->get('view', 'weblinks'); - $layout = $this->input->get('layout', 'default'); - $id = $this->input->getInt('id'); + $this->setRedirect(Route::_('index.php?option=com_weblinks&view=weblinks', false)); + return false; + } - // Check for edit form. - if ($view == 'weblink' && $layout == 'edit' && !$this->checkEditId('com_weblinks.edit.weblink', $id)) - { - // Somehow the person just went to the form - we don't allow that. - if (!\count($this->app->getMessageQueue())) - { - $this->setMessage(Text::sprintf('JLIB_APPLICATION_ERROR_UNHELD_ID', $id), 'error'); - } - - $this->setRedirect(Route::_('index.php?option=com_weblinks&view=weblinks', false)); - - return false; - } - - return parent::display(); - } + return parent::display(); + } } diff --git a/src/administrator/components/com_weblinks/src/Controller/WeblinkController.php b/src/administrator/components/com_weblinks/src/Controller/WeblinkController.php index 6227371..8035403 100644 --- a/src/administrator/components/com_weblinks/src/Controller/WeblinkController.php +++ b/src/administrator/components/com_weblinks/src/Controller/WeblinkController.php @@ -1,4 +1,5 @@ input->getInt('filter_category_id'), 'int'); + /** + * Method override to check if you can add a new record. + * + * @param array $data An array of input data. + * + * @return boolean + * + * @since 1.6 + */ + protected function allowAdd($data = []) + { + $categoryId = ArrayHelper::getValue($data, 'catid', $this->input->getInt('filter_category_id'), 'int'); - if ($categoryId) - { - // If the category has been passed in the URL check it. - return $this->app->getIdentity()->authorise('core.create', $this->option . '.category.' . $categoryId); - } + if ($categoryId) { + // If the category has been passed in the URL check it. + return $this->app->getIdentity()->authorise('core.create', $this->option . '.category.' . $categoryId); + } - // In the absence of better information, revert to the component permissions. - return parent::allowAdd($data); - } + // In the absence of better information, revert to the component permissions. + return parent::allowAdd($data); + } - /** - * Method to check if you can add a new record. - * - * @param array $data An array of input data. - * @param string $key The name of the key for the primary key. - * - * @return boolean - * - * @since 1.6 - */ - protected function allowEdit($data = array(), $key = 'id') - { - $recordId = (int) isset($data[$key]) ? $data[$key] : 0; + /** + * Method to check if you can add a new record. + * + * @param array $data An array of input data. + * @param string $key The name of the key for the primary key. + * + * @return boolean + * + * @since 1.6 + */ + protected function allowEdit($data = [], $key = 'id') + { + $recordId = (int) isset($data[$key]) ? $data[$key] : 0; - // Since there is no asset tracking, fallback to the component permissions. - if (!$recordId) - { - return parent::allowEdit($data, $key); - } + // Since there is no asset tracking, fallback to the component permissions. + if (!$recordId) { + return parent::allowEdit($data, $key); + } - // Get the item. - $item = $this->getModel()->getItem($recordId); + // Get the item. + $item = $this->getModel()->getItem($recordId); - // Since there is no item, return false. - if (empty($item)) - { - return false; - } + // Since there is no item, return false. + if (empty($item)) { + return false; + } - $user = $this->app->getIdentity(); + $user = $this->app->getIdentity(); - // Check if can edit own core.edit.own. - $canEditOwn = $user->authorise('core.edit.own', $this->option . '.category.' . (int) $item->catid) && $item->created_by == $user->id; + // Check if can edit own core.edit.own. + $canEditOwn = $user->authorise('core.edit.own', $this->option . '.category.' . (int) $item->catid) && $item->created_by == $user->id; - // Check the category core.edit permissions. - return $canEditOwn || $user->authorise('core.edit', $this->option . '.category.' . (int) $item->catid); - } + // Check the category core.edit permissions. + return $canEditOwn || $user->authorise('core.edit', $this->option . '.category.' . (int) $item->catid); + } - /** - * Method to run batch operations. - * - * @param object $model The model. - * - * @return boolean True if successful, false otherwise and internal error is set. - * - * @since 1.7 - */ - public function batch($model = null) - { - $this->checkToken(); + /** + * Method to run batch operations. + * + * @param object $model The model. + * + * @return boolean True if successful, false otherwise and internal error is set. + * + * @since 1.7 + */ + public function batch($model = null) + { + $this->checkToken(); - // Set the model - $model = $this->getModel('Weblink', 'Administrator', array()); + // Set the model + $model = $this->getModel('Weblink', 'Administrator', []); - // Preset the redirect - $this->setRedirect(Route::_('index.php?option=com_weblinks&view=weblinks' . $this->getRedirectToListAppend(), false)); + // Preset the redirect + $this->setRedirect(Route::_('index.php?option=com_weblinks&view=weblinks' . $this->getRedirectToListAppend(), false)); - return parent::batch($model); - } + return parent::batch($model); + } - /** - * Function that allows child controller access to model data after the data has been saved. - * - * @param \Joomla\CMS\MVC\Model\BaseDatabaseModel $model The data model object. - * @param array $validData The validated data. - * - * @return void - * - * @since 1.6 - */ - protected function postSaveHook(BaseDatabaseModel $model, $validData = []) - { - $task = $this->getTask(); + /** + * Function that allows child controller access to model data after the data has been saved. + * + * @param \Joomla\CMS\MVC\Model\BaseDatabaseModel $model The data model object. + * @param array $validData The validated data. + * + * @return void + * + * @since 1.6 + */ + protected function postSaveHook(BaseDatabaseModel $model, $validData = []) + { + $task = $this->getTask(); - if ($task == 'save') - { - $this->setRedirect(Route::_('index.php?option=com_weblinks&view=weblinks', false)); - } - } + if ($task == 'save') { + $this->setRedirect(Route::_('index.php?option=com_weblinks&view=weblinks', false)); + } + } } diff --git a/src/administrator/components/com_weblinks/src/Controller/WeblinksController.php b/src/administrator/components/com_weblinks/src/Controller/WeblinksController.php index 9508b7a..f325805 100644 --- a/src/administrator/components/com_weblinks/src/Controller/WeblinksController.php +++ b/src/administrator/components/com_weblinks/src/Controller/WeblinksController.php @@ -1,4 +1,5 @@ true)) - { - return parent::getModel($name, $prefix, $config); - } + /** + * Proxy for getModel + * + * @param string $name The model name. Optional. + * @param string $prefix The class prefix. Optional. + * @param array $config The array of possible config values. Optional. + * + * @return object The model. + * + * @since 1.6 + */ + public function getModel($name = 'Weblink', $prefix = 'Administrator', $config = ['ignore_request' => true]) + { + return parent::getModel($name, $prefix, $config); + } } diff --git a/src/administrator/components/com_weblinks/src/Extension/WeblinksComponent.php b/src/administrator/components/com_weblinks/src/Extension/WeblinksComponent.php index 937cba4..877847f 100644 --- a/src/administrator/components/com_weblinks/src/Extension/WeblinksComponent.php +++ b/src/administrator/components/com_weblinks/src/Extension/WeblinksComponent.php @@ -1,4 +1,5 @@ getRegistry()->register('weblinksadministrator', new AdministratorService); - $this->getRegistry()->register('weblinkicon', new Icon($container->get(SiteApplication::class))); - } - - /** - * Returns a valid section for the given section. If it is not valid then null - * is returned. - * - * @param string $section The section to get the mapping for - * @param object $item The item - * - * @return string|null The new section - * - * @since 4.0.0 - */ - public function validateSection($section, $item = null) - { - if ($section != 'weblink') - { - // We don't know other sections - return null; - } - - return $section; - } - - /** - * Returns valid contexts - * - * @return array - * - * @since 4.0.0 - */ - public function getContexts(): array - { - Factory::getLanguage()->load('com_weblinks', JPATH_ADMINISTRATOR); - - $contexts = array( - 'com_weblinks.weblink' => Text::_('COM_WEBLINKS'), - ); - - return $contexts; - } + /** + * Booting the extension. This is the function to set up the environment of the extension like + * registering new class loaders, etc. + * + * If required, some initial set up can be done from services of the container, eg. + * registering HTML services. + * + * @param ContainerInterface $container The container + * + * @return void + * + * @since 4.0.0 + */ - /** - * Returns the table for the count items functions for the given section. - * - * @param string $section The section - * - * @return string|null - * - * @since 4.0.0 - */ - protected function getTableNameForSection(string $section = null) - { - return ($section === 'category' ? 'categories' : 'weblinks'); - } + public function boot(ContainerInterface $container) + { + $this->getRegistry()->register('weblinksadministrator', new AdministratorService()); + $this->getRegistry()->register('weblinkicon', new Icon($container->get(SiteApplication::class))); + } - /** - * Returns the state column for the count items functions for the given section. - * - * @param string $section The section - * - * @return string|null - * - * @since 4.0.0 - */ - protected function getStateColumnForSection(string $section = null) - { - return 'state'; - } + /** + * Returns a valid section for the given section. If it is not valid then null + * is returned. + * + * @param string $section The section to get the mapping for + * @param object $item The item + * + * @return string|null The new section + * + * @since 4.0.0 + */ + public function validateSection($section, $item = null) + { + if ($section != 'weblink') { + // We don't know other sections + return null; + } + + return $section; + } + + /** + * Returns valid contexts + * + * @return array + * + * @since 4.0.0 + */ + public function getContexts(): array + { + Factory::getLanguage()->load('com_weblinks', JPATH_ADMINISTRATOR); + $contexts = [ + 'com_weblinks.weblink' => Text::_('COM_WEBLINKS'), + ]; + return $contexts; + } + + + /** + * Returns the table for the count items functions for the given section. + * + * @param string $section The section + * + * @return string|null + * + * @since 4.0.0 + */ + protected function getTableNameForSection(string $section = null) + { + return ($section === 'category' ? 'categories' : 'weblinks'); + } + + /** + * Returns the state column for the count items functions for the given section. + * + * @param string $section The section + * + * @return string|null + * + * @since 4.0.0 + */ + protected function getStateColumnForSection(string $section = null) + { + return 'state'; + } } diff --git a/src/administrator/components/com_weblinks/src/Field/Modal/WeblinkField.php b/src/administrator/components/com_weblinks/src/Field/Modal/WeblinkField.php index 07bf11b..f4ad905 100644 --- a/src/administrator/components/com_weblinks/src/Field/Modal/WeblinkField.php +++ b/src/administrator/components/com_weblinks/src/Field/Modal/WeblinkField.php @@ -1,4 +1,5 @@ element['new'] == 'true'); + $allowEdit = ((string) $this->element['edit'] == 'true'); + $allowClear = ((string) $this->element['clear'] != 'false'); + $allowSelect = ((string) $this->element['select'] != 'false'); + // Load language + Factory::getLanguage()->load('com_weblinks', JPATH_ADMINISTRATOR); + // The active weblink id field. + $value = (int) $this->value > 0 ? (int) $this->value : ''; + // Create the modal id. + $modalId = 'Weblink_' . $this->id; + /** @var \Joomla\CMS\WebAsset\WebAssetManager $wa */ + $wa = Factory::getApplication()->getDocument()->getWebAssetManager(); + // Add the modal field script to the document head. + $wa->useScript('field.modal-fields'); + // Script to proxy the select modal function to the modal-fields.js file. + if ($allowSelect) { + static $scriptSelect = null; + if (is_null($scriptSelect)) { + $scriptSelect = []; + } - /** - * Method to get the field input markup. - * - * @return string The field input markup. - * - * @since __DEPLOY_VERSION__ - */ - protected function getInput() - { - $allowNew = ((string) $this->element['new'] == 'true'); - $allowEdit = ((string) $this->element['edit'] == 'true'); - $allowClear = ((string) $this->element['clear'] != 'false'); - $allowSelect = ((string) $this->element['select'] != 'false'); - - // Load language - Factory::getLanguage()->load('com_weblinks', JPATH_ADMINISTRATOR); - - // The active weblink id field. - $value = (int) $this->value > 0 ? (int) $this->value : ''; - - // Create the modal id. - $modalId = 'Weblink_' . $this->id; - - /** @var \Joomla\CMS\WebAsset\WebAssetManager $wa */ - $wa = Factory::getApplication()->getDocument()->getWebAssetManager(); - - // Add the modal field script to the document head. - $wa->useScript('field.modal-fields'); - - // Script to proxy the select modal function to the modal-fields.js file. - if ($allowSelect) - { - static $scriptSelect = null; - - if (is_null($scriptSelect)) - { - $scriptSelect = array(); - } - - if (!isset($scriptSelect[$this->id])) - { - $wa->addInlineScript(" + if (!isset($scriptSelect[$this->id])) { + $wa->addInlineScript( + " window.jSelectWeblink_" . $this->id . " = function (id, title, catid, object, url, language) { window.processModalSelect('Article', '" . $this->id . "', id, title, catid, object, url, language); }", - [], - ['type' => 'module'] - ); + [], + ['type' => 'module'] + ); + Text::script('JGLOBAL_ASSOCIATIONS_PROPAGATE_FAILED'); + $scriptSelect[$this->id] = true; + } + } - Text::script('JGLOBAL_ASSOCIATIONS_PROPAGATE_FAILED'); + // Setup variables for display. + $linkWeblinks = 'index.php?option=com_weblinks&view=weblinks&layout=modal&tmpl=component&' . Session::getFormToken() . '=1'; + $linkWeblink = 'index.php?option=com_weblinks&view=weblink&layout=modal&tmpl=component&' . Session::getFormToken() . '=1'; + $modalTitle = Text::_('COM_WEBLINKS_CHANGE_WEBLINK'); + if (isset($this->element['language'])) { + $linkWeblinks .= '&forcedLanguage=' . $this->element['language']; + $linkWeblink .= '&forcedLanguage=' . $this->element['language']; + $modalTitle .= ' — ' . $this->element['label']; + } - $scriptSelect[$this->id] = true; - } - } + $urlSelect = $linkWeblinks . '&function=jSelectWeblink_' . $this->id; + $urlEdit = $linkWeblink . '&task=weblink.edit&id=\' + document.getElementById("' . $this->id . '_id").value + \''; + $urlNew = $linkWeblink . '&task=weblink.add'; + if ($value) { + $db = Factory::getDbo(); + $query = $db->getQuery(true) + ->select($db->quoteName('title')) + ->from($db->quoteName('#__weblinks')) + ->where($db->quoteName('id') . ' = :id') + ->bind(':id', $value, ParameterType::INTEGER); + $db->setQuery($query); + try { + $title = $db->loadResult(); + } catch (\RuntimeException $e) { + Factory::getApplication()->enqueueMessage($e->getMessage(), 'error'); + } + } - // Setup variables for display. - $linkWeblinks = 'index.php?option=com_weblinks&view=weblinks&layout=modal&tmpl=component&' . Session::getFormToken() . '=1'; - $linkWeblink = 'index.php?option=com_weblinks&view=weblink&layout=modal&tmpl=component&' . Session::getFormToken() . '=1'; - $modalTitle = Text::_('COM_WEBLINKS_CHANGE_WEBLINK'); + $title = empty($title) ? Text::_('COM_WEBLINKS_SELECT_A_WEBLINK') : htmlspecialchars($title, ENT_QUOTES, 'UTF-8'); + // The current weblink display field. + $html = ''; + if ($allowSelect || $allowNew || $allowEdit || $allowClear) { + $html .= ''; + } - if (isset($this->element['language'])) - { - $linkWeblinks .= '&forcedLanguage=' . $this->element['language']; - $linkWeblink .= '&forcedLanguage=' . $this->element['language']; - $modalTitle .= ' — ' . $this->element['label']; - } + $html .= ''; + // Select weblink button + if ($allowSelect) { + $html .= '' + . ' ' . Text::_('JSELECT') + . ''; + } - $urlSelect = $linkWeblinks . '&function=jSelectWeblink_' . $this->id; - $urlEdit = $linkWeblink . '&task=weblink.edit&id=\' + document.getElementById("' . $this->id . '_id").value + \''; - $urlNew = $linkWeblink . '&task=weblink.add'; + // New weblink button + if ($allowNew) { + $html .= '' + . ' ' . Text::_('JACTION_CREATE') + . ''; + } - if ($value) - { - $db = Factory::getDbo(); - $query = $db->getQuery(true) - ->select($db->quoteName('title')) - ->from($db->quoteName('#__weblinks')) - ->where($db->quoteName('id') . ' = :id') - ->bind(':id', $value, ParameterType::INTEGER); - $db->setQuery($query); + // Edit weblink button + if ($allowEdit) { + $html .= '' + . ' ' . Text::_('JACTION_EDIT') + . ''; + } - try - { - $title = $db->loadResult(); - } - catch (\RuntimeException $e) - { - Factory::getApplication()->enqueueMessage($e->getMessage(), 'error'); - } - } + // Clear weblink button + if ($allowClear) { + $html .= '' + . ' ' . Text::_('JCLEAR') + . ''; + } - $title = empty($title) ? Text::_('COM_WEBLINKS_SELECT_A_WEBLINK') : htmlspecialchars($title, ENT_QUOTES, 'UTF-8'); + if ($allowSelect || $allowNew || $allowEdit || $allowClear) { + $html .= ''; + } - // The current weblink display field. - $html = ''; + // Select weblink modal + if ($allowSelect) { + $html .= HTMLHelper::_('bootstrap.renderModal', 'ModalSelect' . $modalId, [ + 'title' => $modalTitle, + 'url' => $urlSelect, + 'height' => '400px', + 'width' => '800px', + 'bodyHeight' => 70, + 'modalWidth' => 80, + 'footer' => '', + ]); + } - if ($allowSelect || $allowNew || $allowEdit || $allowClear) - { - $html .= ''; - } + $closeButtonClick = "window.processModalEdit(this, '$this->id', 'add', 'weblink', 'cancel', 'weblink-form'); return false;"; + $saveButtonClick = "window.processModalEdit(this, '$this->id', 'add', 'weblink', 'save', 'weblink-form'); return false;"; + $applyButtonClick = "window.processModalEdit(this, '$this->id', 'add', 'weblink', 'apply', 'weblink-form'); return false;"; + // New weblink modal + if ($allowNew) { + $html .= HTMLHelper::_('bootstrap.renderModal', 'ModalNew' . $modalId, [ + 'title' => Text::_('COM_WEBLINKS_NEW_WEBLINK'), + 'backdrop' => 'static', + 'keyboard' => false, + 'closeButton' => false, + 'url' => $urlNew, + 'height' => '400px', + 'width' => '800px', + 'bodyHeight' => '70', + 'modalWidth' => '80', + 'footer' => '' + . '' + . '', + ]); + } - $html .= ''; + // Edit weblink modal + if ($allowEdit) { + $html .= HTMLHelper::_('bootstrap.renderModal', 'ModalEdit' . $modalId, [ + 'title' => Text::_('COM_WEBLINKS_EDIT_WEBLINK'), + 'backdrop' => 'static', + 'keyboard' => false, + 'closeButton' => false, + 'url' => $urlEdit, + 'height' => '400px', + 'width' => '800px', + 'bodyHeight' => '70', + 'modalWidth' => '80', + 'footer' => '' + . '' + . '', + ]); + } - // Select weblink button - if ($allowSelect) - { - $html .= '' - . ' ' . Text::_('JSELECT') - . ''; - } + // Note: class='required' for client side validation. + $class = $this->required ? ' class="required modal-value"' : ''; + $html .= ''; + return $html; + } - // New weblink button - if ($allowNew) - { - $html .= '' - . ' ' . Text::_('JACTION_CREATE') - . ''; - } - - // Edit weblink button - if ($allowEdit) - { - $html .= '' - . ' ' . Text::_('JACTION_EDIT') - . ''; - } - - // Clear weblink button - if ($allowClear) - { - $html .= '' - . ' ' . Text::_('JCLEAR') - . ''; - } - - if ($allowSelect || $allowNew || $allowEdit || $allowClear) - { - $html .= ''; - } - - // Select weblink modal - if ($allowSelect) - { - $html .= HTMLHelper::_( - 'bootstrap.renderModal', - 'ModalSelect' . $modalId, - array( - 'title' => $modalTitle, - 'url' => $urlSelect, - 'height' => '400px', - 'width' => '800px', - 'bodyHeight' => 70, - 'modalWidth' => 80, - 'footer' => '', - ) - ); - } - - $closeButtonClick = "window.processModalEdit(this, '$this->id', 'add', 'weblink', 'cancel', 'weblink-form'); return false;"; - $saveButtonClick = "window.processModalEdit(this, '$this->id', 'add', 'weblink', 'save', 'weblink-form'); return false;"; - $applyButtonClick = "window.processModalEdit(this, '$this->id', 'add', 'weblink', 'apply', 'weblink-form'); return false;"; - - // New weblink modal - if ($allowNew) - { - $html .= HTMLHelper::_( - 'bootstrap.renderModal', - 'ModalNew' . $modalId, - array( - 'title' => Text::_('COM_WEBLINKS_NEW_WEBLINK'), - 'backdrop' => 'static', - 'keyboard' => false, - 'closeButton' => false, - 'url' => $urlNew, - 'height' => '400px', - 'width' => '800px', - 'bodyHeight' => '70', - 'modalWidth' => '80', - 'footer' => '' - . '' - . '', - ) - ); - } - - // Edit weblink modal - if ($allowEdit) - { - $html .= HTMLHelper::_( - 'bootstrap.renderModal', - 'ModalEdit' . $modalId, - array( - 'title' => Text::_('COM_WEBLINKS_EDIT_WEBLINK'), - 'backdrop' => 'static', - 'keyboard' => false, - 'closeButton' => false, - 'url' => $urlEdit, - 'height' => '400px', - 'width' => '800px', - 'bodyHeight' => '70', - 'modalWidth' => '80', - 'footer' => '' - . '' - . '', - ) - ); - } - - // Note: class='required' for client side validation. - $class = $this->required ? ' class="required modal-value"' : ''; - $html .= ''; - - return $html; - } - - /** - * Method to get the field label markup. - * - * @return string The field label markup. - * - * @since __DEPLOY_VERSION__ - */ - protected function getLabel() - { - return str_replace($this->id, $this->id . '_name', parent::getLabel()); - } + /** + * Method to get the field label markup. + * + * @return string The field label markup. + * + * @since __DEPLOY_VERSION__ + */ + protected function getLabel() + { + return str_replace($this->id, $this->id . '_name', parent::getLabel()); + } } diff --git a/src/administrator/components/com_weblinks/src/Helper/AssociationsHelper.php b/src/administrator/components/com_weblinks/src/Helper/AssociationsHelper.php index 45d4129..5ee4d89 100644 --- a/src/administrator/components/com_weblinks/src/Helper/AssociationsHelper.php +++ b/src/administrator/components/com_weblinks/src/Helper/AssociationsHelper.php @@ -1,4 +1,5 @@ getType($typeName); + /** + * Get the associated items for an item + * + * @param string $typeName The item type + * @param int $id The id of item for which we need the associated items + * + * @return array + * + * @since __DEPLOY_VERSION__ + */ + public function getAssociations($typeName, $id) + { + $type = $this->getType($typeName); + $context = $this->extension . '.item'; + $catidField = 'catid'; + if ($typeName === 'category') { + $context = 'com_categories.item'; + $catidField = ''; + } - $context = $this->extension . '.item'; - $catidField = 'catid'; + // Get the associations. + $associations = Associations::getAssociations($this->extension, $type['tables']['a'], $context, $id, 'id', 'alias', $catidField); + return $associations; + } - if ($typeName === 'category') - { - $context = 'com_categories.item'; - $catidField = ''; - } + /** + * Get item information + * + * @param string $typeName The item type + * @param int $id The id of item for which we need the associated items + * + * @return Table|null + * + * @since __DEPLOY_VERSION__ + */ + public function getItem($typeName, $id) + { + if (empty($id)) { + return null; + } - // Get the associations. - $associations = Associations::getAssociations( - $this->extension, - $type['tables']['a'], - $context, - $id, - 'id', - 'alias', - $catidField - ); + $table = null; + switch ($typeName) { + case 'weblink': + $table = Table::getInstance('WeblinkTable', 'Joomla\\Component\\Weblinks\\Administrator\\Table\\'); - return $associations; - } + break; + case 'category': + $table = Table::getInstance('Category', 'Joomla\\CMS\\Table\\'); - /** - * Get item information - * - * @param string $typeName The item type - * @param int $id The id of item for which we need the associated items - * - * @return Table|null - * - * @since __DEPLOY_VERSION__ - */ - public function getItem($typeName, $id) - { - if (empty($id)) - { - return null; - } + break; + } - $table = null; + if (empty($table)) { + return null; + } - switch ($typeName) - { - case 'weblink': - $table = Table::getInstance('WeblinkTable', 'Joomla\\Component\\Weblinks\\Administrator\\Table\\'); - break; + $table->load($id); + return $table; + } - case 'category': - $table = Table::getInstance('Category', 'Joomla\\CMS\\Table\\'); - break; - } + /** + * Get information about the type + * + * @param string $typeName The item type + * + * @return array Array of item types + * + * @since __DEPLOY_VERSION__ + */ + public function getType($typeName = '') + { + $fields = $this->getFieldsTemplate(); + $tables = []; + $joins = []; + $support = $this->getSupportTemplate(); + $title = ''; + if (in_array($typeName, $this->itemTypes)) { + switch ($typeName) { + case 'weblink': + $support['state'] = true; + $support['acl'] = true; + $support['checkout'] = true; + $support['category'] = true; + $support['save2copy'] = true; + $tables = [ + 'a' => '#__weblinks', + ]; + $title = 'weblink'; - if (empty($table)) - { - return null; - } + break; + case 'category': + $fields['created_user_id'] = 'a.created_user_id'; + $fields['ordering'] = 'a.lft'; + $fields['level'] = 'a.level'; + $fields['catid'] = ''; + $fields['state'] = 'a.published'; + $support['state'] = true; + $support['acl'] = true; + $support['checkout'] = true; + $support['level'] = true; + $tables = [ + 'a' => '#__categories', + ]; + $title = 'category'; - $table->load($id); + break; + } + } - return $table; - } - - /** - * Get information about the type - * - * @param string $typeName The item type - * - * @return array Array of item types - * - * @since __DEPLOY_VERSION__ - */ - public function getType($typeName = '') - { - $fields = $this->getFieldsTemplate(); - $tables = array(); - $joins = array(); - $support = $this->getSupportTemplate(); - $title = ''; - - if (in_array($typeName, $this->itemTypes)) - { - switch ($typeName) - { - case 'weblink': - - $support['state'] = true; - $support['acl'] = true; - $support['checkout'] = true; - $support['category'] = true; - $support['save2copy'] = true; - - $tables = array( - 'a' => '#__weblinks', - ); - - $title = 'weblink'; - break; - - case 'category': - $fields['created_user_id'] = 'a.created_user_id'; - $fields['ordering'] = 'a.lft'; - $fields['level'] = 'a.level'; - $fields['catid'] = ''; - $fields['state'] = 'a.published'; - - $support['state'] = true; - $support['acl'] = true; - $support['checkout'] = true; - $support['level'] = true; - - $tables = array( - 'a' => '#__categories', - ); - - $title = 'category'; - break; - } - } - - return array( - 'fields' => $fields, - 'support' => $support, - 'tables' => $tables, - 'joins' => $joins, - 'title' => $title, - ); - } + return [ + 'fields' => $fields, + 'support' => $support, + 'tables' => $tables, + 'joins' => $joins, + 'title' => $title, + ]; + } } diff --git a/src/administrator/components/com_weblinks/src/Helper/WeblinksHelper.php b/src/administrator/components/com_weblinks/src/Helper/WeblinksHelper.php index 823b8c7..816b207 100644 --- a/src/administrator/components/com_weblinks/src/Helper/WeblinksHelper.php +++ b/src/administrator/components/com_weblinks/src/Helper/WeblinksHelper.php @@ -1,4 +1,5 @@ id) || $record->state != -2) - { - return false; - } + /** + * Method to test whether a record can be deleted. + * + * @param object $record A record object. + * + * @return boolean True if allowed to delete the record. Defaults to the permission for the component. + * + * @since 1.6 + */ + protected function canDelete($record) + { + if (empty($record->id) || $record->state != -2) { + return false; + } - return $this->getCurrentUser()->authorise('core.delete', 'com_weblinks.category.' . (int) $record->catid); - } + return $this->getCurrentUser()->authorise('core.delete', 'com_weblinks.category.' . (int) $record->catid); + } - /** - * Method to test whether a record can be deleted. - * - * @param object $record A record object. - * - * @return boolean True if allowed to change the state of the record. Defaults to the permission for the component. - * - * @since 1.6 - */ - protected function canEditState($record) - { - if (!empty($record->catid)) - { - return $this->getCurrentUser()->authorise('core.edit.state', 'com_weblinks.category.' . (int) $record->catid); - } + /** + * Method to test whether a record can be deleted. + * + * @param object $record A record object. + * + * @return boolean True if allowed to change the state of the record. Defaults to the permission for the component. + * + * @since 1.6 + */ + protected function canEditState($record) + { + if (!empty($record->catid)) { + return $this->getCurrentUser()->authorise('core.edit.state', 'com_weblinks.category.' . (int) $record->catid); + } - return parent::canEditState($record); - } + return parent::canEditState($record); + } - /** - * Abstract method for getting the form from the model. - * - * @param array $data Data for the form. - * @param boolean $loadData True if the form is to load its own data (default case), false if not. - * - * @return mixed A JForm object on success, false on failure - * - * @since 1.6 - */ - public function getForm($data = array(), $loadData = true) - { - // Get the form. - $form = $this->loadForm('com_weblinks.weblink', 'weblink', array('control' => 'jform', 'load_data' => $loadData)); + /** + * Abstract method for getting the form from the model. + * + * @param array $data Data for the form. + * @param boolean $loadData True if the form is to load its own data (default case), false if not. + * + * @return mixed A JForm object on success, false on failure + * + * @since 1.6 + */ + public function getForm($data = [], $loadData = true) + { + // Get the form. + $form = $this->loadForm('com_weblinks.weblink', 'weblink', ['control' => 'jform', 'load_data' => $loadData]); - if (empty($form)) - { - return false; - } + if (empty($form)) { + return false; + } - // Determine correct permissions to check. - if ($this->getState('weblink.id')) - { - // Existing record. Can only edit in selected categories. - $form->setFieldAttribute('catid', 'action', 'core.edit'); - } - else - { - // New record. Can only create in selected categories. - $form->setFieldAttribute('catid', 'action', 'core.create'); - } + // Determine correct permissions to check. + if ($this->getState('weblink.id')) { + // Existing record. Can only edit in selected categories. + $form->setFieldAttribute('catid', 'action', 'core.edit'); + } else { + // New record. Can only create in selected categories. + $form->setFieldAttribute('catid', 'action', 'core.create'); + } - // Modify the form based on access controls. - if (!$this->canEditState((object) $data)) - { - // Disable fields for display. - $form->setFieldAttribute('ordering', 'disabled', 'true'); - $form->setFieldAttribute('state', 'disabled', 'true'); - $form->setFieldAttribute('publish_up', 'disabled', 'true'); - $form->setFieldAttribute('publish_down', 'disabled', 'true'); + // Modify the form based on access controls. + if (!$this->canEditState((object) $data)) { + // Disable fields for display. + $form->setFieldAttribute('ordering', 'disabled', 'true'); + $form->setFieldAttribute('state', 'disabled', 'true'); + $form->setFieldAttribute('publish_up', 'disabled', 'true'); + $form->setFieldAttribute('publish_down', 'disabled', 'true'); - // Disable fields while saving. - // The controller has already verified this is a record you can edit. - $form->setFieldAttribute('ordering', 'filter', 'unset'); - $form->setFieldAttribute('state', 'filter', 'unset'); - $form->setFieldAttribute('publish_up', 'filter', 'unset'); - $form->setFieldAttribute('publish_down', 'filter', 'unset'); - } + // Disable fields while saving. + // The controller has already verified this is a record you can edit. + $form->setFieldAttribute('ordering', 'filter', 'unset'); + $form->setFieldAttribute('state', 'filter', 'unset'); + $form->setFieldAttribute('publish_up', 'filter', 'unset'); + $form->setFieldAttribute('publish_down', 'filter', 'unset'); + } - // Don't allow to change the created_by user if not allowed to access com_users. - if (!$this->getCurrentUser()->authorise('core.manage', 'com_users')) - { - $form->setFieldAttribute('created_by', 'filter', 'unset'); - } + // Don't allow to change the created_by user if not allowed to access com_users. + if (!$this->getCurrentUser()->authorise('core.manage', 'com_users')) { + $form->setFieldAttribute('created_by', 'filter', 'unset'); + } - return $form; - } + return $form; + } - /** - * Method to get the data that should be injected in the form. - * - * @return array The default data is an empty array. - * - * @since 1.6 - */ - protected function loadFormData() - { - $app = Factory::getApplication(); + /** + * Method to get the data that should be injected in the form. + * + * @return array The default data is an empty array. + * + * @since 1.6 + */ + protected function loadFormData() + { + $app = Factory::getApplication(); - // Check the session for previously entered form data. - $data = $app->getUserState('com_weblinks.edit.weblink.data', array()); + // Check the session for previously entered form data. + $data = $app->getUserState('com_weblinks.edit.weblink.data', []); - if (empty($data)) - { - $data = $this->getItem(); + if (empty($data)) { + $data = $this->getItem(); - // Prime some default values. - if ($this->getState('weblink.id') == 0) - { - $data->set('catid', $app->input->get('catid', $app->getUserState('com_weblinks.weblinks.filter.category_id'), 'int')); - } - } + // Prime some default values. + if ($this->getState('weblink.id') == 0) { + $data->set('catid', $app->input->get('catid', $app->getUserState('com_weblinks.weblinks.filter.category_id'), 'int')); + } + } - $this->preprocessData('com_weblinks.weblink', $data); + $this->preprocessData('com_weblinks.weblink', $data); - return $data; - } + return $data; + } - /** - * Method to get a single record. - * - * @param integer $pk The id of the primary key. - * - * @return mixed Object on success, false on failure. - * - * @since 1.6 - */ - public function getItem($pk = null) - { - if ($item = parent::getItem($pk)) - { - // Convert the metadata field to an array. - $registry = new Registry($item->metadata ?? ''); - $item->metadata = $registry->toArray(); + /** + * Method to get a single record. + * + * @param integer $pk The id of the primary key. + * + * @return mixed Object on success, false on failure. + * + * @since 1.6 + */ + public function getItem($pk = null) + { + if ($item = parent::getItem($pk)) { + // Convert the metadata field to an array. + $registry = new Registry($item->metadata ?? ''); + $item->metadata = $registry->toArray(); - // Convert the images field to an array. - $registry = new Registry($item->images ?? ''); - $item->images = $registry->toArray(); + // Convert the images field to an array. + $registry = new Registry($item->images ?? ''); + $item->images = $registry->toArray(); - // Load associated web links items - $assoc = Associations::isEnabled(); + // Load associated web links items + $assoc = Associations::isEnabled(); - if ($assoc) - { - $item->associations = array(); + if ($assoc) { + $item->associations = []; - if ($item->id != null) - { - $associations = Associations::getAssociations('com_weblinks', '#__weblinks', 'com_weblinks.item', $item->id); + if ($item->id != null) { + $associations = Associations::getAssociations('com_weblinks', '#__weblinks', 'com_weblinks.item', $item->id); - foreach ($associations as $tag => $association) - { - $item->associations[$tag] = $association->id; - } - } - } + foreach ($associations as $tag => $association) { + $item->associations[$tag] = $association->id; + } + } + } - if (!empty($item->id)) - { - $item->tags = new TagsHelper; - $item->tags->getTagIds($item->id, 'com_weblinks.weblink'); - $item->metadata['tags'] = $item->tags; - } - } + if (!empty($item->id)) { + $item->tags = new TagsHelper(); + $item->tags->getTagIds($item->id, 'com_weblinks.weblink'); + $item->metadata['tags'] = $item->tags; + } + } - return $item; - } + return $item; + } - /** - * Prepare and sanitise the table data prior to saving. - * - * @param \Joomla\CMS\Table\Table $table A reference to a JTable object. - * - * @return void - * - * @since 1.6 - */ - protected function prepareTable($table) - { - $date = Factory::getDate(); - $user = $this->getCurrentUser(); + /** + * Prepare and sanitise the table data prior to saving. + * + * @param \Joomla\CMS\Table\Table $table A reference to a JTable object. + * + * @return void + * + * @since 1.6 + */ + protected function prepareTable($table) + { + $date = Factory::getDate(); + $user = $this->getCurrentUser(); - $table->title = htmlspecialchars_decode($table->title, ENT_QUOTES); - $table->alias = ApplicationHelper::stringURLSafe($table->alias); + $table->title = htmlspecialchars_decode($table->title, ENT_QUOTES); + $table->alias = ApplicationHelper::stringURLSafe($table->alias); - if (empty($table->alias)) - { - $table->alias = ApplicationHelper::stringURLSafe($table->title); - } + if (empty($table->alias)) { + $table->alias = ApplicationHelper::stringURLSafe($table->title); + } - if (empty($table->id)) - { - // Set the values + if (empty($table->id)) { + // Set the values - // Set ordering to the last item if not set - if (empty($table->ordering)) - { - $db = $this->getDatabase(); - $query = $db->getQuery(true) - ->select('MAX(ordering)') - ->from($db->quoteName('#__weblinks')); + // Set ordering to the last item if not set + if (empty($table->ordering)) { + $db = $this->getDatabase(); + $query = $db->getQuery(true) + ->select('MAX(ordering)') + ->from($db->quoteName('#__weblinks')); - $db->setQuery($query); - $max = $db->loadResult(); + $db->setQuery($query); + $max = $db->loadResult(); - $table->ordering = $max + 1; - } - else - { - // Set the values - $table->modified = $date->toSql(); - $table->modified_by = $user->id; - } - } + $table->ordering = $max + 1; + } else { + // Set the values + $table->modified = $date->toSql(); + $table->modified_by = $user->id; + } + } - // Increment the weblink version number. - $table->version++; - } + // Increment the weblink version number. + $table->version++; + } - /** - * A protected method to get a set of ordering conditions. - * - * @param \Joomla\CMS\Table\Table $table A JTable object. - * - * @return array An array of conditions to add to ordering queries. - * - * @since 1.6 - */ - protected function getReorderConditions($table) - { - $condition = array(); - $condition[] = 'catid = ' . (int) $table->catid; + /** + * A protected method to get a set of ordering conditions. + * + * @param \Joomla\CMS\Table\Table $table A JTable object. + * + * @return array An array of conditions to add to ordering queries. + * + * @since 1.6 + */ + protected function getReorderConditions($table) + { + $condition = []; + $condition[] = 'catid = ' . (int) $table->catid; - return $condition; - } + return $condition; + } - /** - * Method to save the form data. - * - * @param array $data The form data. - * - * @return boolean True on success. - * - * @since 3.1 - */ - public function save($data) - { - $app = Factory::getApplication(); + /** + * Method to save the form data. + * + * @param array $data The form data. + * + * @return boolean True on success. + * + * @since 3.1 + */ + public function save($data) + { + $app = Factory::getApplication(); - // Cast catid to integer for comparison - $catid = (int) $data['catid']; + // Cast catid to integer for comparison + $catid = (int) $data['catid']; - // Check if New Category exists - if ($catid > 0) - { - $catid = CategoriesHelper::validateCategoryId($data['catid'], 'com_weblinks'); - } + // Check if New Category exists + if ($catid > 0) { + $catid = CategoriesHelper::validateCategoryId($data['catid'], 'com_weblinks'); + } - // Save New Category - if ($catid == 0 && $this->canCreateCategory()) - { - $table = array(); - $table['title'] = $data['catid']; - $table['parent_id'] = 1; - $table['extension'] = 'com_weblinks'; - $table['language'] = $data['language']; - $table['published'] = 1; + // Save New Category + if ($catid == 0 && $this->canCreateCategory()) { + $table = []; + $table['title'] = $data['catid']; + $table['parent_id'] = 1; + $table['extension'] = 'com_weblinks'; + $table['language'] = $data['language']; + $table['published'] = 1; - // Create new category and get catid back - $data['catid'] = CategoriesHelper::createCategory($table); - } + // Create new category and get catid back + $data['catid'] = CategoriesHelper::createCategory($table); + } - // Alter the title for save as copy - if ($app->input->get('task') == 'save2copy') - { - [$name, $alias] = $this->generateNewTitle($data['catid'], $data['alias'], $data['title']); - $data['title'] = $name; - $data['alias'] = $alias; - $data['state'] = 0; - } + // Alter the title for save as copy + if ($app->input->get('task') == 'save2copy') { + [$name, $alias] = $this->generateNewTitle($data['catid'], $data['alias'], $data['title']); + $data['title'] = $name; + $data['alias'] = $alias; + $data['state'] = 0; + } - return parent::save($data); - } + return parent::save($data); + } - /** - * Method to change the title & alias. - * - * @param integer $category_id The id of the parent. - * @param string $alias The alias. - * @param string $name The title. - * - * @return array Contains the modified title and alias. - * - * @since 3.1 - */ - protected function generateNewTitle($category_id, $alias, $name) - { - // Alter the title & alias - $table = $this->getTable(); + /** + * Method to change the title & alias. + * + * @param integer $category_id The id of the parent. + * @param string $alias The alias. + * @param string $name The title. + * + * @return array Contains the modified title and alias. + * + * @since 3.1 + */ + protected function generateNewTitle($category_id, $alias, $name) + { + // Alter the title & alias + $table = $this->getTable(); - while ($table->load(array('alias' => $alias, 'catid' => $category_id))) - { - if ($name == $table->title) - { - $name = StringHelper::increment($name); - } + while ($table->load(['alias' => $alias, 'catid' => $category_id])) { + if ($name == $table->title) { + $name = StringHelper::increment($name); + } - $alias = StringHelper::increment($alias, 'dash'); - } + $alias = StringHelper::increment($alias, 'dash'); + } - return array($name, $alias); - } + return [$name, $alias]; + } - /** - * Allows preprocessing of the JForm object. - * - * @param \JForm $form The form object - * @param array $data The data to be merged into the form object - * @param string $group The plugin group to be executed - * - * @return void - * - * @since 3.6.0 - */ - protected function preprocessForm(\JForm $form, $data, $group = 'content') - { - if ($this->canCreateCategory()) - { - $form->setFieldAttribute('catid', 'allowAdd', 'true'); - } + /** + * Allows preprocessing of the JForm object. + * + * @param \JForm $form The form object + * @param array $data The data to be merged into the form object + * @param string $group The plugin group to be executed + * + * @return void + * + * @since 3.6.0 + */ + protected function preprocessForm(\JForm $form, $data, $group = 'content') + { + if ($this->canCreateCategory()) { + $form->setFieldAttribute('catid', 'allowAdd', 'true'); + } - // Association weblinks items - if (Associations::isEnabled()) - { - $languages = LanguageHelper::getContentLanguages(false, false, null, 'ordering', 'asc'); + // Association weblinks items + if (Associations::isEnabled()) { + $languages = LanguageHelper::getContentLanguages(false, false, null, 'ordering', 'asc'); - if (count($languages) > 1) - { - $addform = new \SimpleXMLElement('
'); - $fields = $addform->addChild('fields'); - $fields->addAttribute('name', 'associations'); - $fieldset = $fields->addChild('fieldset'); - $fieldset->addAttribute('name', 'item_associations'); + if (count($languages) > 1) { + $addform = new \SimpleXMLElement(''); + $fields = $addform->addChild('fields'); + $fields->addAttribute('name', 'associations'); + $fieldset = $fields->addChild('fieldset'); + $fieldset->addAttribute('name', 'item_associations'); - foreach ($languages as $language) - { - $field = $fieldset->addChild('field'); - $field->addAttribute('name', $language->lang_code); - $field->addAttribute('type', 'modal_weblink'); - $field->addAttribute('language', $language->lang_code); - $field->addAttribute('label', $language->title); - $field->addAttribute('translate_label', 'false'); - $field->addAttribute('select', 'true'); - $field->addAttribute('new', 'true'); - $field->addAttribute('edit', 'true'); - $field->addAttribute('clear', 'true'); - $field->addAttribute('addfieldprefix', 'Joomla\\Component\\Weblinks\\Administrator\\Field'); - } + foreach ($languages as $language) { + $field = $fieldset->addChild('field'); + $field->addAttribute('name', $language->lang_code); + $field->addAttribute('type', 'modal_weblink'); + $field->addAttribute('language', $language->lang_code); + $field->addAttribute('label', $language->title); + $field->addAttribute('translate_label', 'false'); + $field->addAttribute('select', 'true'); + $field->addAttribute('new', 'true'); + $field->addAttribute('edit', 'true'); + $field->addAttribute('clear', 'true'); + $field->addAttribute('addfieldprefix', 'Joomla\\Component\\Weblinks\\Administrator\\Field'); + } - $form->load($addform, false); - } - } + $form->load($addform, false); + } + } - parent::preprocessForm($form, $data, $group); - } + parent::preprocessForm($form, $data, $group); + } - /** - * Is the user allowed to create an on the fly category? - * - * @return bool - * - * @since 3.6.0 - */ - private function canCreateCategory() - { - return $this->getCurrentUser()->authorise('core.create', 'com_weblinks'); - } + /** + * Is the user allowed to create an on the fly category? + * + * @return bool + * + * @since 3.6.0 + */ + private function canCreateCategory() + { + return $this->getCurrentUser()->authorise('core.create', 'com_weblinks'); + } } diff --git a/src/administrator/components/com_weblinks/src/Model/WeblinksModel.php b/src/administrator/components/com_weblinks/src/Model/WeblinksModel.php index 6a127f6..33339a8 100644 --- a/src/administrator/components/com_weblinks/src/Model/WeblinksModel.php +++ b/src/administrator/components/com_weblinks/src/Model/WeblinksModel.php @@ -1,4 +1,5 @@ input->get('forcedLanguage', '', 'cmd'); + $forcedLanguage = $app->input->get('forcedLanguage', '', 'cmd'); - // Adjust the context to support modal layouts. - if ($layout = $app->input->get('layout')) - { - $this->context .= '.' . $layout; - } + // Adjust the context to support modal layouts. + if ($layout = $app->input->get('layout')) { + $this->context .= '.' . $layout; + } - // Adjust the context to support forced languages. - if ($forcedLanguage) - { - $this->context .= '.' . $forcedLanguage; - } + // Adjust the context to support forced languages. + if ($forcedLanguage) { + $this->context .= '.' . $forcedLanguage; + } - // Load the parameters. - $params = ComponentHelper::getParams('com_weblinks'); - $this->setState('params', $params); + // Load the parameters. + $params = ComponentHelper::getParams('com_weblinks'); + $this->setState('params', $params); - // Force a language. - if (!empty($forcedLanguage)) - { - $this->setState('filter.language', $forcedLanguage); - } + // Force a language. + if (!empty($forcedLanguage)) { + $this->setState('filter.language', $forcedLanguage); + } - // List state information. - parent::populateState($ordering, $direction); - } + // List state information. + parent::populateState($ordering, $direction); + } - /** - * Method to get a store id based on model configuration state. - * - * This is necessary because the model is used by the component and - * different modules that might need different sets of data or different - * ordering requirements. - * - * @param string $id A prefix for the store id. - * - * @return string A store id. - * - * @since 1.6 - */ - protected function getStoreId($id = '') - { - // Compile the store id. - $id .= ':' . $this->getState('filter.search'); - $id .= ':' . $this->getState('filter.access'); - $id .= ':' . $this->getState('filter.published'); - $id .= ':' . $this->getState('filter.category_id'); - $id .= ':' . $this->getState('filter.language'); - $id .= ':' . $this->getState('filter.tag'); - $id .= ':' . $this->getState('filter.level'); + /** + * Method to get a store id based on model configuration state. + * + * This is necessary because the model is used by the component and + * different modules that might need different sets of data or different + * ordering requirements. + * + * @param string $id A prefix for the store id. + * + * @return string A store id. + * + * @since 1.6 + */ + protected function getStoreId($id = '') + { + // Compile the store id. + $id .= ':' . $this->getState('filter.search'); + $id .= ':' . $this->getState('filter.access'); + $id .= ':' . $this->getState('filter.published'); + $id .= ':' . $this->getState('filter.category_id'); + $id .= ':' . $this->getState('filter.language'); + $id .= ':' . $this->getState('filter.tag'); + $id .= ':' . $this->getState('filter.level'); - return parent::getStoreId($id); - } + return parent::getStoreId($id); + } - /** - * Build an SQL query to load the list data. - * - * @return \JDatabaseQuery - * - * @since 1.6 - */ - protected function getListQuery() - { - // Create a new query object. - $db = $this->getDatabase(); - $query = $db->getQuery(true); - $user = $this->getCurrentUser(); + /** + * Build an SQL query to load the list data. + * + * @return \JDatabaseQuery + * + * @since 1.6 + */ + protected function getListQuery() + { + // Create a new query object. + $db = $this->getDatabase(); + $query = $db->getQuery(true); + $user = $this->getCurrentUser(); - // Select the required fields from the table. - $query->select( - $this->getState( - 'list.select', - 'a.id, a.title, a.alias, a.checked_out, a.checked_out_time, a.catid, a.created, a.created_by, ' . - 'a.hits, a.state, a.access, a.ordering, a.language, a.publish_up, a.publish_down' - ) - ); - $query->from($db->quoteName('#__weblinks', 'a')); + // Select the required fields from the table. + $query->select( + $this->getState( + 'list.select', + 'a.id, a.title, a.alias, a.checked_out, a.checked_out_time, a.catid, a.created, a.created_by, ' . + 'a.hits, a.state, a.access, a.ordering, a.language, a.publish_up, a.publish_down' + ) + ); + $query->from($db->quoteName('#__weblinks', 'a')); - // Join over the language - $query->select($db->quoteName('l.title', 'language_title')) - ->select($db->quoteName('l.image', 'language_image')) - ->join('LEFT', $db->quoteName('#__languages', 'l') . ' ON ' . $db->qn('l.lang_code') . ' = ' . $db->qn('a.language')); + // Join over the language + $query->select($db->quoteName('l.title', 'language_title')) + ->select($db->quoteName('l.image', 'language_image')) + ->join('LEFT', $db->quoteName('#__languages', 'l') . ' ON ' . $db->qn('l.lang_code') . ' = ' . $db->qn('a.language')); - // Join over the users for the checked out user. - $query->select($db->quoteName('uc.name', 'editor')) - ->join('LEFT', $db->quoteName('#__users', 'uc') . ' ON ' . $db->qn('uc.id') . ' = ' . $db->qn('a.checked_out')); + // Join over the users for the checked out user. + $query->select($db->quoteName('uc.name', 'editor')) + ->join('LEFT', $db->quoteName('#__users', 'uc') . ' ON ' . $db->qn('uc.id') . ' = ' . $db->qn('a.checked_out')); - // Join over the asset groups. - $query->select($db->quoteName('ag.title', 'access_level')) - ->join('LEFT', $db->quoteName('#__viewlevels', 'ag') . ' ON ' . $db->qn('ag.id') . ' = ' . $db->qn('a.access')); + // Join over the asset groups. + $query->select($db->quoteName('ag.title', 'access_level')) + ->join('LEFT', $db->quoteName('#__viewlevels', 'ag') . ' ON ' . $db->qn('ag.id') . ' = ' . $db->qn('a.access')); - // Join over the categories. - $query->select('c.title AS category_title') - ->join('LEFT', $db->quoteName('#__categories', 'c') . ' ON ' . $db->qn('c.id') . ' = ' . $db->qn('a.catid')); + // Join over the categories. + $query->select('c.title AS category_title') + ->join('LEFT', $db->quoteName('#__categories', 'c') . ' ON ' . $db->qn('c.id') . ' = ' . $db->qn('a.catid')); - // Join over the associations. - $assoc = Associations::isEnabled(); + // Join over the associations. + $assoc = Associations::isEnabled(); - if ($assoc) - { - $query->select('COUNT(asso2.id)>1 AS association') - ->join('LEFT', $db->quoteName('#__associations', 'asso') . ' ON asso.id = a.id AND asso.context = ' . $db->quote('com_weblinks.item')) - ->join('LEFT', $db->quoteName('#__associations', 'asso2') . ' ON asso2.key = asso.key') - ->group('a.id, l.title, l.image, uc.name, ag.title, c.title'); - } + if ($assoc) { + $query->select('COUNT(asso2.id)>1 AS association') + ->join('LEFT', $db->quoteName('#__associations', 'asso') . ' ON asso.id = a.id AND asso.context = ' . $db->quote('com_weblinks.item')) + ->join('LEFT', $db->quoteName('#__associations', 'asso2') . ' ON asso2.key = asso.key') + ->group('a.id, l.title, l.image, uc.name, ag.title, c.title'); + } - // Filter by access level. - if ($access = $this->getState('filter.access')) - { - $query->where($db->quoteName('a.access') . ' = :access') - ->bind(':access', $access, ParameterType::INTEGER); - } + // Filter by access level. + if ($access = $this->getState('filter.access')) { + $query->where($db->quoteName('a.access') . ' = :access') + ->bind(':access', $access, ParameterType::INTEGER); + } - // Implement View Level Access - if (!$user->authorise('core.admin')) - { - $query->whereIn($db->quoteName('a.access'), $user->getAuthorisedViewLevels()); - } + // Implement View Level Access + if (!$user->authorise('core.admin')) { + $query->whereIn($db->quoteName('a.access'), $user->getAuthorisedViewLevels()); + } - // Filter by published state - $published = (string) $this->getState('filter.published'); + // Filter by published state + $published = (string) $this->getState('filter.published'); - if (is_numeric($published)) - { - $query->where($db->quoteName('a.state') . ' = :state') - ->bind(':state', $published, ParameterType::INTEGER); - } - elseif ($published === '') - { - $query->whereIn($db->quoteName('a.state'), [0, 1]); - } + if (is_numeric($published)) { + $query->where($db->quoteName('a.state') . ' = :state') + ->bind(':state', $published, ParameterType::INTEGER); + } elseif ($published === '') { + $query->whereIn($db->quoteName('a.state'), [0, 1]); + } - // Filter by category. - $categoryId = $this->getState('filter.category_id'); + // Filter by category. + $categoryId = $this->getState('filter.category_id'); - if (is_numeric($categoryId)) - { - $query->where($db->quoteName('a.catid') . ' = :catid') - ->bind(':catid', $categoryId, ParameterType::INTEGER); - } + if (is_numeric($categoryId)) { + $query->where($db->quoteName('a.catid') . ' = :catid') + ->bind(':catid', $categoryId, ParameterType::INTEGER); + } - // Filter on the level. - if ($level = $this->getState('filter.level')) - { - $query->where($db->quoteName('c.level') . ' <= :level') - ->bind(':level', $level, ParameterType::INTEGER); - } + // Filter on the level. + if ($level = $this->getState('filter.level')) { + $query->where($db->quoteName('c.level') . ' <= :level') + ->bind(':level', $level, ParameterType::INTEGER); + } - // Filter by search in title - $search = $this->getState('filter.search'); + // Filter by search in title + $search = $this->getState('filter.search'); - if (!empty($search)) - { - if (stripos($search, 'id:') === 0) - { - $search = substr($search, 3); - $query->where($db->quoteName('a.id') . ' = :id') - ->bind(':id', $search, ParameterType::INTEGER); - } - else - { - $search = '%' . str_replace(' ', '%', $db->escape(trim($search), true) . '%'); - $query->where('(' . $db->quoteName('a.title') . ' LIKE :title OR ' . $db->quoteName('a.alias') . ' LIKE :alias)') - ->bind(':title', $search) - ->bind(':alias', $search); - } - } + if (!empty($search)) { + if (stripos($search, 'id:') === 0) { + $search = substr($search, 3); + $query->where($db->quoteName('a.id') . ' = :id') + ->bind(':id', $search, ParameterType::INTEGER); + } else { + $search = '%' . str_replace(' ', '%', $db->escape(trim($search), true) . '%'); + $query->where('(' . $db->quoteName('a.title') . ' LIKE :title OR ' . $db->quoteName('a.alias') . ' LIKE :alias)') + ->bind(':title', $search) + ->bind(':alias', $search); + } + } - // Filter on the language. - if ($language = $this->getState('filter.language')) - { - $query->where($db->quoteName('a.language') . ' = :language') - ->bind(':language', $language); - } + // Filter on the language. + if ($language = $this->getState('filter.language')) { + $query->where($db->quoteName('a.language') . ' = :language') + ->bind(':language', $language); + } - $tagId = $this->getState('filter.tag'); + $tagId = $this->getState('filter.tag'); - // Filter by a single tag. - if (is_numeric($tagId)) - { - $query->where($db->quoteName('tagmap.tag_id') . ' = :tagId') - ->bind(':tagId', $tagId, ParameterType::INTEGER) - ->join( - 'LEFT', $db->quoteName('#__contentitem_tag_map', 'tagmap') - . ' ON ' . $db->quoteName('tagmap.content_item_id') . ' = ' . $db->quoteName('a.id') - . ' AND ' . $db->quoteName('tagmap.type_alias') . ' = ' . $db->quote('com_weblinks.weblink') - ); - } + // Filter by a single tag. + if (is_numeric($tagId)) { + $query->where($db->quoteName('tagmap.tag_id') . ' = :tagId') + ->bind(':tagId', $tagId, ParameterType::INTEGER) + ->join( + 'LEFT', + $db->quoteName('#__contentitem_tag_map', 'tagmap') + . ' ON ' . $db->quoteName('tagmap.content_item_id') . ' = ' . $db->quoteName('a.id') + . ' AND ' . $db->quoteName('tagmap.type_alias') . ' = ' . $db->quote('com_weblinks.weblink') + ); + } - // Add the list ordering clause. - $orderCol = $this->state->get('list.ordering', 'a.title'); - $orderDirn = $this->state->get('list.direction', 'ASC'); + // Add the list ordering clause. + $orderCol = $this->state->get('list.ordering', 'a.title'); + $orderDirn = $this->state->get('list.direction', 'ASC'); - if ($orderCol == 'a.ordering' || $orderCol == 'category_title') - { - $orderCol = 'c.title ' . $orderDirn . ', a.ordering'; - } + if ($orderCol == 'a.ordering' || $orderCol == 'category_title') { + $orderCol = 'c.title ' . $orderDirn . ', a.ordering'; + } - $query->order($db->escape($orderCol . ' ' . $orderDirn)); + $query->order($db->escape($orderCol . ' ' . $orderDirn)); - return $query; - } + return $query; + } } diff --git a/src/administrator/components/com_weblinks/src/Service/HTML/AdministratorService.php b/src/administrator/components/com_weblinks/src/Service/HTML/AdministratorService.php index 98c560e..8d0944e 100644 --- a/src/administrator/components/com_weblinks/src/Service/HTML/AdministratorService.php +++ b/src/administrator/components/com_weblinks/src/Service/HTML/AdministratorService.php @@ -1,4 +1,5 @@ $associated) { + $associations[$tag] = (int) $associated->id; + } - // Get the associations - if ($associations = Associations::getAssociations('com_weblinks', '#__weblinks', 'com_weblinks.item', $weblinkid)) - { - foreach ($associations as $tag => $associated) - { - $associations[$tag] = (int) $associated->id; - } + // Get the associated contact items + $db = Factory::getDbo(); + $query = $db->getQuery(true) + ->select([ + $db->quoteName('c.id'), + $db->quoteName('c.title', 'title'), + $db->quoteName('l.sef', 'lang_sef'), + $db->quoteName('lang_code'), + $db->quoteName('cat.title', 'category_title'), + $db->quoteName('l.image'), + $db->quoteName('l.title', 'language_title'), + ]) + ->from($db->quoteName('#__weblinks', 'c')) + ->join('LEFT', $db->quoteName('#__categories', 'cat'), $db->quoteName('cat.id') . ' = ' . $db->quoteName('c.catid')) + ->join('LEFT', $db->quoteName('#__languages', 'l'), $db->quoteName('c.language') . ' = ' . $db->quoteName('l.lang_code')) + ->whereIn($db->quoteName('c.id'), array_values($associations)) + ->where($db->quoteName('c.id') . ' != :id') + ->bind(':id', $weblinkid, ParameterType::INTEGER); + $db->setQuery($query); + try { + $items = $db->loadObjectList('id'); + } catch (\RuntimeException $e) { + throw new \Exception($e->getMessage(), 500, $e); + } - // Get the associated contact items - $db = Factory::getDbo(); - $query = $db->getQuery(true) - ->select( - [ - $db->quoteName('c.id'), - $db->quoteName('c.title', 'title'), - $db->quoteName('l.sef', 'lang_sef'), - $db->quoteName('lang_code'), - $db->quoteName('cat.title', 'category_title'), - $db->quoteName('l.image'), - $db->quoteName('l.title', 'language_title'), - ] - ) - ->from($db->quoteName('#__weblinks', 'c')) - ->join('LEFT', $db->quoteName('#__categories', 'cat'), $db->quoteName('cat.id') . ' = ' . $db->quoteName('c.catid')) - ->join('LEFT', $db->quoteName('#__languages', 'l'), $db->quoteName('c.language') . ' = ' . $db->quoteName('l.lang_code')) - ->whereIn($db->quoteName('c.id'), array_values($associations)) - ->where($db->quoteName('c.id') . ' != :id') - ->bind(':id', $weblinkid, ParameterType::INTEGER); - $db->setQuery($query); + if ($items) { + $app = Factory::getApplication(); + $languages = LanguageHelper::getContentLanguages([0, 1]); + $content_languages = array_column($languages, 'lang_code'); + foreach ($items as &$item) { + if (in_array($item->lang_code, $content_languages)) { + $text = $item->lang_code; + $url = Route::_('index.php?option=com_weblinks&task=weblink.edit&id=' . (int) $item->id); + $tooltip = '' . htmlspecialchars($item->language_title, ENT_QUOTES, 'UTF-8') . '
' + . htmlspecialchars($item->title, ENT_QUOTES, 'UTF-8') + . '
' . Text::sprintf('JCATEGORY_SPRINTF', $item->category_title); + $classes = 'badge bg-secondary'; + $item->link = '' . $text . '' + . ''; + } else { + // Display warning if Content Language is trashed or deleted + $app->enqueueMessage(Text::sprintf('JGLOBAL_ASSOCIATIONS_CONTENTLANGUAGE_WARNING', $item->lang_code), 'warning'); + } + } + } - try - { - $items = $db->loadObjectList('id'); - } - catch (\RuntimeException $e) - { - throw new \Exception($e->getMessage(), 500, $e); - } + $html = LayoutHelper::render('joomla.content.associations', $items); + } - if ($items) - { - $app = Factory::getApplication(); - $languages = LanguageHelper::getContentLanguages(array(0, 1)); - $content_languages = array_column($languages, 'lang_code'); - - foreach ($items as &$item) - { - if (in_array($item->lang_code, $content_languages)) - { - $text = $item->lang_code; - $url = Route::_('index.php?option=com_weblinks&task=weblink.edit&id=' . (int) $item->id); - $tooltip = '' . htmlspecialchars($item->language_title, ENT_QUOTES, 'UTF-8') . '
' - . htmlspecialchars($item->title, ENT_QUOTES, 'UTF-8') - . '
' . Text::sprintf('JCATEGORY_SPRINTF', $item->category_title); - $classes = 'badge bg-secondary'; - - $item->link = '' . $text . '' - . ''; - } - else - { - // Display warning if Content Language is trashed or deleted - $app->enqueueMessage(Text::sprintf('JGLOBAL_ASSOCIATIONS_CONTENTLANGUAGE_WARNING', $item->lang_code), 'warning'); - } - } - } - - $html = LayoutHelper::render('joomla.content.associations', $items); - } - - return $html; - } + return $html; + } } diff --git a/src/administrator/components/com_weblinks/src/Service/HTML/Icon.php b/src/administrator/components/com_weblinks/src/Service/HTML/Icon.php index 35ece5b..a209017 100644 --- a/src/administrator/components/com_weblinks/src/Service/HTML/Icon.php +++ b/src/administrator/components/com_weblinks/src/Service/HTML/Icon.php @@ -1,4 +1,5 @@ application = $application; + } - /** - * Service constructor - * - * @param CMSApplication $application The application - * - * @since 4.0.0 - */ - public function __construct(CMSApplication $application) - { - $this->application = $application; - } + /** + * Method to generate a link to the create item page for the given category + * + * @param object $category The category information + * @param Registry $params The item parameters + * @param array $attribs Optional attributes for the link + * + * @return string The HTML markup for the create item link + * + * @since 4.0.0 + */ + public static function create($category, $params, $attribs = []) + { + $uri = Uri::getInstance(); + $url = 'index.php?option=com_weblinks&task=weblink.add&return=' . base64_encode($uri) . '&w_id=0&catid=' . $category->id; + $text = LayoutHelper::render('joomla.content.icons.create', ['params' => $params, 'legacy' => false]); + // Add the button classes to the attribs array + if (isset($attribs['class'])) { + $attribs['class'] .= ' btn btn-primary'; + } else { + $attribs['class'] = 'btn btn-primary'; + } - /** - * Method to generate a link to the create item page for the given category - * - * @param object $category The category information - * @param Registry $params The item parameters - * @param array $attribs Optional attributes for the link - * - * @return string The HTML markup for the create item link - * - * @since 4.0.0 - */ - public static function create($category, $params, $attribs = array()) - { - $uri = Uri::getInstance(); + $button = HTMLHelper::_('link', Route::_($url), $text, $attribs); + $output = '' . $button . ''; + return $output; + } - $url = 'index.php?option=com_weblinks&task=weblink.add&return=' . base64_encode($uri) . '&w_id=0&catid=' . $category->id; + /** + * Display an edit icon for the weblink. + * + * This icon will not display in a popup window, nor if the weblink is trashed. + * Edit access checks must be performed in the calling code. + * + * @param object $weblink The weblink information + * @param Registry $params The item parameters + * @param array $attribs Optional attributes for the link + * @param boolean $legacy True to use legacy images, false to use icomoon based graphic + * + * @return string The HTML for the weblink edit icon. + * + * @since 4.0.0 + */ + public static function edit($weblink, $params, $attribs = [], $legacy = false) + { + $user = Factory::getApplication()->getIdentity(); + $uri = Uri::getInstance(); + // Ignore if in a popup window. + if ($params && $params->get('popup')) { + return ''; + } - $text = LayoutHelper::render('joomla.content.icons.create', array('params' => $params, 'legacy' => false)); + // Ignore if the state is negative (trashed). + if ($weblink->state < 0) { + return ''; + } - // Add the button classes to the attribs array - if (isset($attribs['class'])) - { - $attribs['class'] .= ' btn btn-primary'; - } - else - { - $attribs['class'] = 'btn btn-primary'; - } + // Show checked_out icon if the contact is checked out by a different user + if ( + property_exists($weblink, 'checked_out') + && property_exists($weblink, 'checked_out_time') + && $weblink->checked_out + && $weblink->checked_out !== $user->get('id') + ) { + $checkoutUser = Factory::getUser($weblink->checked_out); + $date = HTMLHelper::_('date', $weblink->checked_out_time); + $tooltip = Text::sprintf('COM_WEBLINKS_CHECKED_OUT_BY', $checkoutUser->name) + . '
' . $date; + $text = LayoutHelper::render('joomla.content.icons.edit_lock', ['contact' => $weblink, 'tooltip' => $tooltip, 'legacy' => $legacy]); + $attribs['aria-describedby'] = 'editweblink-' . (int) $weblink->id; + $output = HTMLHelper::_('link', '#', $text, $attribs); + return $output; + } - $button = HTMLHelper::_('link', Route::_($url), $text, $attribs); + $weblinkUrl = RouteHelper::getWeblinkRoute($weblink->slug, $weblink->catid, $weblink->language); + $url = $weblinkUrl . '&task=weblink.edit&w_id=' . $weblink->id . '&return=' . base64_encode($uri); + if ((int) $weblink->state === 0) { + $tooltip = Text::_('COM_WEBLINKS_EDIT_UNPUBLISHED_WEBLINK'); + } else { + $tooltip = Text::_('COM_WEBLINKS_EDIT_PUBLISHED_WEBLINK'); + } - $output = '' . $button . ''; + $nowDate = strtotime(Factory::getDate()); + $icon = $weblink->state ? 'edit' : 'eye-slash'; - return $output; - } + if ( + ($weblink->publish_up !== null && strtotime($weblink->publish_up) > $nowDate) + || ($weblink->publish_down !== null && strtotime($weblink->publish_down) < $nowDate + && $weblink->publish_down !== Factory::getDbo()->getNullDate()) + ) { + $icon = 'eye-slash'; + } - /** - * Display an edit icon for the weblink. - * - * This icon will not display in a popup window, nor if the weblink is trashed. - * Edit access checks must be performed in the calling code. - * - * @param object $weblink The weblink information - * @param Registry $params The item parameters - * @param array $attribs Optional attributes for the link - * @param boolean $legacy True to use legacy images, false to use icomoon based graphic - * - * @return string The HTML for the weblink edit icon. - * - * @since 4.0.0 - */ - public static function edit($weblink, $params, $attribs = array(), $legacy = false) - { - $user = Factory::getApplication()->getIdentity(); - $uri = Uri::getInstance(); - - // Ignore if in a popup window. - if ($params && $params->get('popup')) - { - return ''; - } - - // Ignore if the state is negative (trashed). - if ($weblink->state < 0) - { - return ''; - } - - // Show checked_out icon if the contact is checked out by a different user - if (property_exists($weblink, 'checked_out') - && property_exists($weblink, 'checked_out_time') - && $weblink->checked_out - && $weblink->checked_out !== $user->get('id')) - { - $checkoutUser = Factory::getUser($weblink->checked_out); - $date = HTMLHelper::_('date', $weblink->checked_out_time); - $tooltip = Text::sprintf('COM_WEBLINKS_CHECKED_OUT_BY', $checkoutUser->name) - . '
' . $date; - - $text = LayoutHelper::render('joomla.content.icons.edit_lock', array('contact' => $weblink, 'tooltip' => $tooltip, 'legacy' => $legacy)); - - $attribs['aria-describedby'] = 'editweblink-' . (int) $weblink->id; - $output = HTMLHelper::_('link', '#', $text, $attribs); - - return $output; - } - - $weblinkUrl = RouteHelper::getWeblinkRoute($weblink->slug, $weblink->catid, $weblink->language); - $url = $weblinkUrl . '&task=weblink.edit&w_id=' . $weblink->id . '&return=' . base64_encode($uri); - - if ((int) $weblink->state === 0) - { - $tooltip = Text::_('COM_WEBLINKS_EDIT_UNPUBLISHED_WEBLINK'); - } - else - { - $tooltip = Text::_('COM_WEBLINKS_EDIT_PUBLISHED_WEBLINK'); - } - - $nowDate = strtotime(Factory::getDate()); - $icon = $weblink->state ? 'edit' : 'eye-slash'; - - if (($weblink->publish_up !== null && strtotime($weblink->publish_up) > $nowDate) - || ($weblink->publish_down !== null && strtotime($weblink->publish_down) < $nowDate - && $weblink->publish_down !== Factory::getDbo()->getNullDate())) - { - $icon = 'eye-slash'; - } - - $aria_described = 'editweblink-' . (int) $weblink->id; - - $text = ''; - $text .= Text::_('JGLOBAL_EDIT'); - $text .= ''; - - $attribs['aria-describedby'] = $aria_described; - $output = HTMLHelper::_('link', Route::_($url), $text, $attribs); - - return $output; - } + $aria_described = 'editweblink-' . (int) $weblink->id; + $text = ''; + $text .= Text::_('JGLOBAL_EDIT'); + $text .= ''; + $attribs['aria-describedby'] = $aria_described; + $output = HTMLHelper::_('link', Route::_($url), $text, $attribs); + return $output; + } } diff --git a/src/administrator/components/com_weblinks/src/Table/WeblinkTable.php b/src/administrator/components/com_weblinks/src/Table/WeblinkTable.php index b43612b..b23d59b 100644 --- a/src/administrator/components/com_weblinks/src/Table/WeblinkTable.php +++ b/src/administrator/components/com_weblinks/src/Table/WeblinkTable.php @@ -1,4 +1,5 @@ typeAlias = 'com_weblinks.weblink'; + protected $_supportNullValue = true; + /** + * Ensure the params and metadata in json encoded in the bind method + * + * @var array + * @since 3.4 + */ + protected $_jsonEncode = ['params', 'metadata', 'images']; + /** + * Constructor + * + * @param \JDatabaseDriver &$db A database connector object + * + * @since 1.5 + */ + public function __construct($db) + { + $this->typeAlias = 'com_weblinks.weblink'; + parent::__construct('#__weblinks', 'id', $db); + // Set the published column alias + $this->setColumnAlias('published', 'state'); + } - parent::__construct('#__weblinks', 'id', $db); + /** + * Overload the store method for the Weblinks table. + * + * @param boolean $updateNulls Toggle whether null values should be updated. + * + * @return boolean True on success, false on failure. + * + * @since 1.6 + */ + public function store($updateNulls = true) + { + $date = Factory::getDate()->toSql(); + $user = Factory::getApplication()->getIdentity(); + $this->modified = $date; + if ($this->id) { + // Existing item + $this->modified_by = $user->id; + $this->modified = $date; + } else { + // New weblink. A weblink created and created_by field can be set by the user, + // so we don't touch either of these if they are set. + if (!(int) $this->created) { + $this->created = $date; + } - // Set the published column alias - $this->setColumnAlias('published', 'state'); - } + if (empty($this->created_by)) { + $this->created_by = $user->id; + } - /** - * Overload the store method for the Weblinks table. - * - * @param boolean $updateNulls Toggle whether null values should be updated. - * - * @return boolean True on success, false on failure. - * - * @since 1.6 - */ - public function store($updateNulls = true) - { - $date = Factory::getDate()->toSql(); - $user = Factory::getApplication()->getIdentity(); + if (!(int) $this->modified) { + $this->modified = $date; + } - $this->modified = $date; + if (empty($this->modified_by)) { + $this->modified_by = $user->id; + } - if ($this->id) - { - // Existing item - $this->modified_by = $user->id; - $this->modified = $date; - } - else - { - // New weblink. A weblink created and created_by field can be set by the user, - // so we don't touch either of these if they are set. - if (!(int) $this->created) - { - $this->created = $date; - } + if (empty($this->hits)) { + $this->hits = 0; + } + } - if (empty($this->created_by)) - { - $this->created_by = $user->id; - } + // Set publish_up to null if not set + if (!$this->publish_up) { + $this->publish_up = null; + } - if (!(int) $this->modified) - { - $this->modified = $date; - } + // Set publish_down to null if not set + if (!$this->publish_down) { + $this->publish_down = null; + } - if (empty($this->modified_by)) - { - $this->modified_by = $user->id; - } + // Verify that the alias is unique + $table = new WeblinkTable($this->getDbo()); - if (empty($this->hits)) - { - $this->hits = 0; - } - } + if ( + $table->load(['language' => $this->language, 'alias' => $this->alias, 'catid' => (int) $this->catid]) + && ($table->id != $this->id || $this->id == 0) + ) { + $this->setError(Text::_('COM_WEBLINKS_ERROR_UNIQUE_ALIAS')); + return false; + } - // Set publish_up to null if not set - if (!$this->publish_up) - { - $this->publish_up = null; - } + // Convert IDN urls to punycode + $this->url = PunycodeHelper::urlToPunycode($this->url); + return parent::store($updateNulls); + } - // Set publish_down to null if not set - if (!$this->publish_down) - { - $this->publish_down = null; - } + /** + * Overloaded check method to ensure data integrity. + * + * @return boolean True on success. + * + * @since 1.5 + */ + public function check() + { + if (InputFilter::checkAttribute(['href', $this->url])) { + $this->setError(Text::_('COM_WEBLINKS_ERR_TABLES_PROVIDE_URL')); + return false; + } - // Verify that the alias is unique - $table = new WeblinkTable($this->getDbo()); + // Check for valid name + if (trim($this->title) == '') { + $this->setError(Text::_('COM_WEBLINKS_ERR_TABLES_TITLE')); + return false; + } - if ($table->load(array('language' => $this->language, 'alias' => $this->alias, 'catid' => (int) $this->catid)) - && ($table->id != $this->id || $this->id == 0)) - { - $this->setError(Text::_('COM_WEBLINKS_ERROR_UNIQUE_ALIAS')); + // Check for existing name + $db = $this->getDbo(); + $query = $db->getQuery(true) + ->select($db->quoteName('id')) + ->from($db->quoteName('#__weblinks')) + ->where($db->quoteName('title') . ' = :title') + ->where($db->quoteName('language') . ' = :language') + ->where($db->quoteName('catid') . ' = :catid') + ->bind(':title', $this->title) + ->bind(':language', $this->language) + ->bind(':catid', $this->catid, ParameterType::INTEGER); + $db->setQuery($query); + $xid = (int) $db->loadResult(); + if ($xid && $xid != (int) $this->id) { + $this->setError(Text::_('COM_WEBLINKS_ERR_TABLES_NAME')); + return false; + } - return false; - } + if (empty($this->alias)) { + $this->alias = $this->title; + } - // Convert IDN urls to punycode - $this->url = PunycodeHelper::urlToPunycode($this->url); + $this->alias = ApplicationHelper::stringURLSafe($this->alias, $this->language); + if (trim(str_replace('-', '', $this->alias)) == '') { + $this->alias = Factory::getDate()->format("Y-m-d-H-i-s"); + } - return parent::store($updateNulls); - } + // Check the publish down date is not earlier than publish up. + if ((int) $this->publish_down > 0 && $this->publish_down < $this->publish_up) { + $this->setError(Text::_('JGLOBAL_START_PUBLISH_AFTER_FINISH')); + return false; + } - /** - * Overloaded check method to ensure data integrity. - * - * @return boolean True on success. - * - * @since 1.5 - */ - public function check() - { - if (InputFilter::checkAttribute(array('href', $this->url))) - { - $this->setError(Text::_('COM_WEBLINKS_ERR_TABLES_PROVIDE_URL')); + /* + * Clean up keywords -- eliminate extra spaces between phrases + * and cr (\r) and lf (\n) characters from string + */ + if (!empty($this->metakey)) { + // Array of characters to remove + $bad_characters = ["\n", "\r", "\"", "<", ">"]; + $after_clean = StringHelper::str_ireplace($bad_characters, "", $this->metakey); + $keys = explode(',', $after_clean); + $clean_keys = []; + foreach ($keys as $key) { + // Ignore blank keywords + if (trim($key)) { + $clean_keys[] = trim($key); + } + } - return false; - } + // Put array back together delimited by ", " + $this->metakey = implode(", ", $clean_keys); + } - // Check for valid name - if (trim($this->title) == '') - { - $this->setError(Text::_('COM_WEBLINKS_ERR_TABLES_TITLE')); + /** + * Ensure any new items have compulsory fields set. This is needed for things like + * frontend editing where we don't show all the fields or using some kind of API + */ + if (!$this->id) { + if (!isset($this->xreference)) { + $this->xreference = ''; + } - return false; - } + if (!isset($this->metakey)) { + $this->metakey = ''; + } - // Check for existing name - $db = $this->getDbo(); + if (!isset($this->metadesc)) { + $this->metadesc = ''; + } - $query = $db->getQuery(true) - ->select($db->quoteName('id')) - ->from($db->quoteName('#__weblinks')) - ->where($db->quoteName('title') . ' = :title') - ->where($db->quoteName('language') . ' = :language') - ->where($db->quoteName('catid') . ' = :catid') - ->bind(':title', $this->title) - ->bind(':language', $this->language) - ->bind(':catid', $this->catid, ParameterType::INTEGER); - $db->setQuery($query); + if (!isset($this->images)) { + $this->images = '{}'; + } - $xid = (int) $db->loadResult(); + if (!isset($this->metadata)) { + $this->metadata = '{}'; + } - if ($xid && $xid != (int) $this->id) - { - $this->setError(Text::_('COM_WEBLINKS_ERR_TABLES_NAME')); + if (!isset($this->params)) { + $this->params = '{}'; + } + } - return false; - } + return parent::check(); + } - if (empty($this->alias)) - { - $this->alias = $this->title; - } - - $this->alias = ApplicationHelper::stringURLSafe($this->alias, $this->language); - - if (trim(str_replace('-', '', $this->alias)) == '') - { - $this->alias = Factory::getDate()->format("Y-m-d-H-i-s"); - } - - // Check the publish down date is not earlier than publish up. - if ((int) $this->publish_down > 0 && $this->publish_down < $this->publish_up) - { - $this->setError(Text::_('JGLOBAL_START_PUBLISH_AFTER_FINISH')); - - return false; - } - - /* - * Clean up keywords -- eliminate extra spaces between phrases - * and cr (\r) and lf (\n) characters from string - */ - if (!empty($this->metakey)) - { - // Array of characters to remove - $bad_characters = array("\n", "\r", "\"", "<", ">"); - $after_clean = StringHelper::str_ireplace($bad_characters, "", $this->metakey); - $keys = explode(',', $after_clean); - $clean_keys = array(); - - foreach ($keys as $key) - { - // Ignore blank keywords - if (trim($key)) - { - $clean_keys[] = trim($key); - } - } - - // Put array back together delimited by ", " - $this->metakey = implode(", ", $clean_keys); - } - - /** - * Ensure any new items have compulsory fields set. This is needed for things like - * frontend editing where we don't show all the fields or using some kind of API - */ - if (!$this->id) - { - if (!isset($this->xreference)) - { - $this->xreference = ''; - } - - if (!isset($this->metakey)) - { - $this->metakey = ''; - } - - if (!isset($this->metadesc)) - { - $this->metadesc = ''; - } - - if (!isset($this->images)) - { - $this->images = '{}'; - } - - if (!isset($this->metadata)) - { - $this->metadata = '{}'; - } - - if (!isset($this->params)) - { - $this->params = '{}'; - } - } - - return parent::check(); - } - - /** - * Get the type alias for the history table - * - * @return string The alias as described above - * - * @since 4.0.0 - */ - public function getTypeAlias() - { - return $this->typeAlias; - } + /** + * Get the type alias for the history table + * + * @return string The alias as described above + * + * @since 4.0.0 + */ + public function getTypeAlias() + { + return $this->typeAlias; + } } diff --git a/src/administrator/components/com_weblinks/src/View/Weblink/HtmlView.php b/src/administrator/components/com_weblinks/src/View/Weblink/HtmlView.php index 0eb467c..ce3826c 100644 --- a/src/administrator/components/com_weblinks/src/View/Weblink/HtmlView.php +++ b/src/administrator/components/com_weblinks/src/View/Weblink/HtmlView.php @@ -1,4 +1,5 @@ state = $this->get('State'); - $this->item = $this->get('Item'); - $this->form = $this->get('Form'); + /** + * Display the view. + * + * @param string $tpl The name of the template file to parse; automatically searches through the template paths. + * + * @return mixed A string if successful, otherwise an Error object. + */ + public function display($tpl = null) + { + $this->state = $this->get('State'); + $this->item = $this->get('Item'); + $this->form = $this->get('Form'); - // Check for errors. - if (count($errors = $this->get('Errors'))) - { - throw new GenericDataException(implode("\n", $errors), 500); - } + // Check for errors. + if (count($errors = $this->get('Errors'))) { + throw new GenericDataException(implode("\n", $errors), 500); + } - // If we are forcing a language in modal (used for associations). - if ($this->getLayout() === 'modal' && $forcedLanguage = Factory::getApplication()->input->get('forcedLanguage', '', 'cmd')) - { - // Set the language field to the forcedLanguage and disable changing it. - $this->form->setValue('language', null, $forcedLanguage); - $this->form->setFieldAttribute('language', 'readonly', 'true'); + // If we are forcing a language in modal (used for associations). + if ($this->getLayout() === 'modal' && $forcedLanguage = Factory::getApplication()->input->get('forcedLanguage', '', 'cmd')) { + // Set the language field to the forcedLanguage and disable changing it. + $this->form->setValue('language', null, $forcedLanguage); + $this->form->setFieldAttribute('language', 'readonly', 'true'); - // Only allow to select categories with All language or with the forced language. - $this->form->setFieldAttribute('catid', 'language', '*,' . $forcedLanguage); + // Only allow to select categories with All language or with the forced language. + $this->form->setFieldAttribute('catid', 'language', '*,' . $forcedLanguage); - // Only allow to select tags with All language or with the forced language. - $this->form->setFieldAttribute('tags', 'language', '*,' . $forcedLanguage); - } + // Only allow to select tags with All language or with the forced language. + $this->form->setFieldAttribute('tags', 'language', '*,' . $forcedLanguage); + } - $this->addToolbar(); + $this->addToolbar(); - parent::display($tpl); - } + parent::display($tpl); + } - /** - * Add the page title and toolbar. - * - * @return void - * - * @since 1.6 - */ - protected function addToolbar() - { - $app = Factory::getApplication(); - $app->input->set('hidemainmenu', true); + /** + * Add the page title and toolbar. + * + * @return void + * + * @since 1.6 + */ + protected function addToolbar() + { + $app = Factory::getApplication(); + $app->input->set('hidemainmenu', true); - $user = $this->getCurrentUser(); - $isNew = ($this->item->id == 0); - $checkedOut = $this->item->checked_out && $this->item->checked_out !== $user->get('id'); + $user = $this->getCurrentUser(); + $isNew = ($this->item->id == 0); + $checkedOut = $this->item->checked_out && $this->item->checked_out !== $user->get('id'); - // Since we don't track these assets at the item level, use the category id. - $canDo = ContentHelper::getActions('com_weblinks', 'category', $this->item->catid); + // Since we don't track these assets at the item level, use the category id. + $canDo = ContentHelper::getActions('com_weblinks', 'category', $this->item->catid); - ToolbarHelper::title($isNew ? Text::_('COM_WEBLINKS_MANAGER_WEBLINK_NEW') : Text::_('COM_WEBLINKS_MANAGER_WEBLINK_EDIT'), 'link weblinks'); + ToolbarHelper::title($isNew ? Text::_('COM_WEBLINKS_MANAGER_WEBLINK_NEW') : Text::_('COM_WEBLINKS_MANAGER_WEBLINK_EDIT'), 'link weblinks'); - // Build the actions for new and existing records. - if ($isNew) - { - // For new records, check the create permission. - if (count($user->getAuthorisedCategories('com_weblinks', 'core.create')) > 0) - { - ToolbarHelper::apply('weblink.apply'); + // Build the actions for new and existing records. + if ($isNew) { + // For new records, check the create permission. + if (count($user->getAuthorisedCategories('com_weblinks', 'core.create')) > 0) { + ToolbarHelper::apply('weblink.apply'); - ToolbarHelper::saveGroup( - [ - ['save', 'weblink.save'], - ['save2new', 'weblink.save2new'] - ], - 'btn-success' - ); - } + ToolbarHelper::saveGroup( + [ + ['save', 'weblink.save'], + ['save2new', 'weblink.save2new'], + ], + 'btn-success' + ); + } - ToolbarHelper::cancel('weblink.cancel'); - } - else - { - // Since it's an existing record, check the edit permission, or fall back to edit own if the owner. - $itemEditable = $canDo->get('core.edit') || ($canDo->get('core.edit.own') && $this->item->created_by == $user->id); + ToolbarHelper::cancel('weblink.cancel'); + } else { + // Since it's an existing record, check the edit permission, or fall back to edit own if the owner. + $itemEditable = $canDo->get('core.edit') || ($canDo->get('core.edit.own') && $this->item->created_by == $user->id); - $toolbarButtons = []; + $toolbarButtons = []; - // Can't save the record if it's checked out and editable - if (!$checkedOut && $itemEditable) - { - ToolbarHelper::apply('weblink.apply'); + // Can't save the record if it's checked out and editable + if (!$checkedOut && $itemEditable) { + ToolbarHelper::apply('weblink.apply'); - $toolbarButtons[] = ['save', 'weblink.save']; + $toolbarButtons[] = ['save', 'weblink.save']; - // We can save this record, but check the create permission to see if we can return to make a new one. - if ($canDo->get('core.create')) - { - $toolbarButtons[] = ['save2new', 'weblink.save2new']; - } - } + // We can save this record, but check the create permission to see if we can return to make a new one. + if ($canDo->get('core.create')) { + $toolbarButtons[] = ['save2new', 'weblink.save2new']; + } + } - // If checked out, we can still save - if ($canDo->get('core.create')) - { - $toolbarButtons[] = ['save2copy', 'weblink.save2copy']; - } + // If checked out, we can still save + if ($canDo->get('core.create')) { + $toolbarButtons[] = ['save2copy', 'weblink.save2copy']; + } - ToolbarHelper::saveGroup( - $toolbarButtons, - 'btn-success' - ); + ToolbarHelper::saveGroup( + $toolbarButtons, + 'btn-success' + ); - ToolbarHelper::cancel('weblink.cancel', 'JTOOLBAR_CLOSE'); + ToolbarHelper::cancel('weblink.cancel', 'JTOOLBAR_CLOSE'); - if (ComponentHelper::isEnabled('com_contenthistory') && $this->state->params->get('save_history', 0) && $itemEditable) - { - ToolbarHelper::versions('com_weblinks.weblink', $this->item->id); - } + if (ComponentHelper::isEnabled('com_contenthistory') && $this->state->params->get('save_history', 0) && $itemEditable) { + ToolbarHelper::versions('com_weblinks.weblink', $this->item->id); + } - if (Associations::isEnabled() && ComponentHelper::isEnabled('com_associations')) - { - ToolbarHelper::custom('weblink.editAssociations', 'contract', '', 'JTOOLBAR_ASSOCIATIONS', false, false); - } - } + if (Associations::isEnabled() && ComponentHelper::isEnabled('com_associations')) { + ToolbarHelper::custom('weblink.editAssociations', 'contract', '', 'JTOOLBAR_ASSOCIATIONS', false, false); + } + } - ToolbarHelper::help('Components_Weblinks_Links_Edit'); - } + ToolbarHelper::help('Components_Weblinks_Links_Edit'); + } } diff --git a/src/administrator/components/com_weblinks/src/View/Weblinks/HtmlView.php b/src/administrator/components/com_weblinks/src/View/Weblinks/HtmlView.php index ce87434..9d2d036 100644 --- a/src/administrator/components/com_weblinks/src/View/Weblinks/HtmlView.php +++ b/src/administrator/components/com_weblinks/src/View/Weblinks/HtmlView.php @@ -1,4 +1,5 @@ state = $this->get('State'); - $this->items = $this->get('Items'); - $this->pagination = $this->get('Pagination'); - $this->filterForm = $this->get('FilterForm'); - $this->activeFilters = $this->get('ActiveFilters'); + /** + * Display the view. + * + * @param string $tpl The name of the template file to parse; automatically searches through the template paths. + * + * @return mixed A string if successful, otherwise an Error object. + */ + public function display($tpl = null) + { + $this->state = $this->get('State'); + $this->items = $this->get('Items'); + $this->pagination = $this->get('Pagination'); + $this->filterForm = $this->get('FilterForm'); + $this->activeFilters = $this->get('ActiveFilters'); - // Check for errors. - if (count($errors = $this->get('Errors'))) - { - throw new GenericDataException(implode("\n", $errors), 500); - } + // Check for errors. + if (count($errors = $this->get('Errors'))) { + throw new GenericDataException(implode("\n", $errors), 500); + } - if (!\count($this->items) && $this->isEmptyState = $this->get('IsEmptyState')) - { - $this->setLayout('emptystate'); - } + if (!\count($this->items) && $this->isEmptyState = $this->get('IsEmptyState')) { + $this->setLayout('emptystate'); + } - // We don't need toolbar in the modal layout. - if ($this->getLayout() !== 'modal') - { - $this->addToolbar(); - } - else - { - // In article associations modal we need to remove language filter if forcing a language. - // We also need to change the category filter to show show categories with All or the forced language. - if ($forcedLanguage = Factory::getApplication()->input->get('forcedLanguage', '', 'CMD')) - { - // If the language is forced we can't allow to select the language, so transform the language selector filter into an hidden field. - $languageXml = new \SimpleXMLElement(''); - $this->filterForm->setField($languageXml, 'filter', true); + // We don't need toolbar in the modal layout. + if ($this->getLayout() !== 'modal') { + $this->addToolbar(); + } else { + // In article associations modal we need to remove language filter if forcing a language. + // We also need to change the category filter to show show categories with All or the forced language. + if ($forcedLanguage = Factory::getApplication()->input->get('forcedLanguage', '', 'CMD')) { + // If the language is forced we can't allow to select the language, so transform the language selector filter into an hidden field. + $languageXml = new \SimpleXMLElement(''); + $this->filterForm->setField($languageXml, 'filter', true); - // Also, unset the active language filter so the search tools is not open by default with this filter. - unset($this->activeFilters['language']); + // Also, unset the active language filter so the search tools is not open by default with this filter. + unset($this->activeFilters['language']); - // One last changes needed is to change the category filter to just show categories with All language or with the forced language. - $this->filterForm->setFieldAttribute('category_id', 'language', '*,' . $forcedLanguage, 'filter'); - } - } + // One last changes needed is to change the category filter to just show categories with All language or with the forced language. + $this->filterForm->setFieldAttribute('category_id', 'language', '*,' . $forcedLanguage, 'filter'); + } + } - parent::display($tpl); - } + parent::display($tpl); + } - /** - * Add the page title and toolbar. - * - * @return void - * - * @since 1.6 - */ - protected function addToolbar() - { - $canDo = ContentHelper::getActions('com_weblinks', 'category', $this->state->get('filter.category_id')); - $user = $this->getCurrentUser(); + /** + * Add the page title and toolbar. + * + * @return void + * + * @since 1.6 + */ + protected function addToolbar() + { + $canDo = ContentHelper::getActions('com_weblinks', 'category', $this->state->get('filter.category_id')); + $user = $this->getCurrentUser(); - // Get the toolbar object instance - $toolbar = Toolbar::getInstance('toolbar'); + // Get the toolbar object instance + $toolbar = Toolbar::getInstance('toolbar'); - ToolbarHelper::title(Text::_('COM_WEBLINKS_MANAGER_WEBLINKS'), 'link weblinks'); + ToolbarHelper::title(Text::_('COM_WEBLINKS_MANAGER_WEBLINKS'), 'link weblinks'); - if ($canDo->get('core.create') || \count($user->getAuthorisedCategories('com_weblinks', 'core.create')) > 0) - { - ToolbarHelper::addNew('weblink.add'); - } + if ($canDo->get('core.create') || \count($user->getAuthorisedCategories('com_weblinks', 'core.create')) > 0) { + ToolbarHelper::addNew('weblink.add'); + } - if (!$this->isEmptyState && $canDo->get('core.edit.state')) - { - $dropdown = $toolbar->dropdownButton('status-group') - ->text('JTOOLBAR_CHANGE_STATUS') - ->toggleSplit(false) - ->icon('icon-ellipsis-h') - ->buttonClass('btn btn-action') - ->listCheck(true); + if (!$this->isEmptyState && $canDo->get('core.edit.state')) { + $dropdown = $toolbar->dropdownButton('status-group') + ->text('JTOOLBAR_CHANGE_STATUS') + ->toggleSplit(false) + ->icon('icon-ellipsis-h') + ->buttonClass('btn btn-action') + ->listCheck(true); - $childBar = $dropdown->getChildToolbar(); + $childBar = $dropdown->getChildToolbar(); - $childBar->publish('weblinks.publish')->listCheck(true); + $childBar->publish('weblinks.publish')->listCheck(true); - $childBar->unpublish('weblinks.unpublish')->listCheck(true); + $childBar->unpublish('weblinks.unpublish')->listCheck(true); - $childBar->archive('weblinks.archive')->listCheck(true); + $childBar->archive('weblinks.archive')->listCheck(true); - if ($user->authorise('core.admin')) - { - $childBar->checkin('weblinks.checkin')->listCheck(true); - } + if ($user->authorise('core.admin')) { + $childBar->checkin('weblinks.checkin')->listCheck(true); + } - if ($this->state->get('filter.published') != -2) - { - $childBar->trash('weblinks.trash')->listCheck(true); - } + if ($this->state->get('filter.published') != -2) { + $childBar->trash('weblinks.trash')->listCheck(true); + } - // Add a batch button - if ($user->authorise('core.create', 'com_weblinks') - && $user->authorise('core.edit', 'com_weblinks') - && $user->authorise('core.edit.state', 'com_weblinks')) - { - $childBar->popupButton('batch') - ->text('JTOOLBAR_BATCH') - ->selector('collapseModal') - ->listCheck(true); - } - } + // Add a batch button + if ( + $user->authorise('core.create', 'com_weblinks') + && $user->authorise('core.edit', 'com_weblinks') + && $user->authorise('core.edit.state', 'com_weblinks') + ) { + $childBar->popupButton('batch') + ->text('JTOOLBAR_BATCH') + ->selector('collapseModal') + ->listCheck(true); + } + } - if (!$this->isEmptyState && $this->state->get('filter.published') == -2 && $canDo->get('core.delete')) - { - $toolbar->delete('weblinks.delete') - ->text('JTOOLBAR_EMPTY_TRASH') - ->message('JGLOBAL_CONFIRM_DELETE') - ->listCheck(true); - } + if (!$this->isEmptyState && $this->state->get('filter.published') == -2 && $canDo->get('core.delete')) { + $toolbar->delete('weblinks.delete') + ->text('JTOOLBAR_EMPTY_TRASH') + ->message('JGLOBAL_CONFIRM_DELETE') + ->listCheck(true); + } - if ($user->authorise('core.admin', 'com_weblinks') || $user->authorise('core.options', 'com_weblinks')) - { - ToolbarHelper::preferences('com_weblinks'); - } + if ($user->authorise('core.admin', 'com_weblinks') || $user->authorise('core.options', 'com_weblinks')) { + ToolbarHelper::preferences('com_weblinks'); + } - ToolbarHelper::help('Components_Weblinks_Links'); - } + ToolbarHelper::help('Components_Weblinks_Links'); + } } diff --git a/src/administrator/components/com_weblinks/tmpl/weblink/edit.php b/src/administrator/components/com_weblinks/tmpl/weblink/edit.php index fff3838..4d1b292 100644 --- a/src/administrator/components/com_weblinks/tmpl/weblink/edit.php +++ b/src/administrator/components/com_weblinks/tmpl/weblink/edit.php @@ -1,4 +1,5 @@ input; - $assoc = Associations::isEnabled(); - // Fieldsets to not automatically render by /layouts/joomla/edit/params.php $this->ignore_fieldsets = array('details', 'images', 'item_associations', 'jmetadata'); $this->useCoreUI = true; - // In case of modal $isModal = $input->get('layout') == 'modal' ? true : false; $layout = $isModal ? 'modal' : 'edit'; @@ -35,81 +32,87 @@ $tmpl = $isModal || $input->get('tmpl', '', 'cmd') === 'component' ? '&tmpl=c - + -
- 'details')); ?> +
+ 'details')); ?> - item->id) ? Text::_('COM_WEBLINKS_NEW_WEBLINK', true) : Text::_('COM_WEBLINKS_EDIT_WEBLINK', true)); ?> -
-
-
-
-
- form->renderField('url'); ?> - form->renderField('description'); ?> -
-
-
-
-
- -
-
- + item->id) ? Text::_('COM_WEBLINKS_NEW_WEBLINK', true) : Text::_('COM_WEBLINKS_EDIT_WEBLINK', true)); ?> +
+
+
+
+
+ form->renderField('url'); ?> + form->renderField('description'); ?> +
+
+
+
+
+ +
+
+ - -
-
-
- -
- form->renderField('imaJGLOBAL_FIELDSET_IMAGE_OPTIONSges'); ?> - form->getGroup('images') as $field) : ?> - renderField(); ?> - -
-
-
-
+ +
+
+
+ +
+ form->renderField('imaJGLOBAL_FIELDSET_IMAGE_OPTIONSges'); ?> + form->getGroup('images') as $field) : + ?> + renderField(); ?> + +
+
+
+
- + - -
-
-
- - -
-
-
-
- - -
-
-
- + +
+
+
+ + +
+
+
+
+ + +
+
+
+ - + - - -
- - -
- - - - + + +
+ + +
+ + + + - + -
+
- - - + + + diff --git a/src/administrator/components/com_weblinks/tmpl/weblink/edit_associations.php b/src/administrator/components/com_weblinks/tmpl/weblink/edit_associations.php index 731f5d3..4c9be9f 100644 --- a/src/administrator/components/com_weblinks/tmpl/weblink/edit_associations.php +++ b/src/administrator/components/com_weblinks/tmpl/weblink/edit_associations.php @@ -1,4 +1,5 @@ form->getFieldsets('params'); ?> - $fieldSet) : ?> -
- description) && trim($fieldSet->description)) : ?> - ' . $this->escape(Text::_($fieldSet->description)) . '

'; ?> - - form->getFieldset($name) as $field) : ?> -
-
label; ?>
-
input; ?>
-
- -
- + $fieldSet) : + ?> +
+ description) && trim($fieldSet->description)) : + ?> + ' . $this->escape(Text::_($fieldSet->description)) . '

'; ?> + + form->getFieldset($name) as $field) : + ?> +
+
label; ?>
+
input; ?>
+
+ +
+ diff --git a/src/administrator/components/com_weblinks/tmpl/weblink/modal.php b/src/administrator/components/com_weblinks/tmpl/weblink/modal.php index 0dbf7be..dbb905f 100644 --- a/src/administrator/components/com_weblinks/tmpl/weblink/modal.php +++ b/src/administrator/components/com_weblinks/tmpl/weblink/modal.php @@ -1,4 +1,5 @@ 'bottom')); - // @deprecated 4.0 the function parameter, the inline js and the buttons are not needed since 3.7.0. $function = Factory::getApplication()->input->getCmd('function', 'jEditWeblink_' . (int) $this->item->id); - // Function to update input title when changed Factory::getDocument()->addScriptDeclaration(' function jEditWeblinkModal() { @@ -30,6 +30,6 @@ Factory::getDocument()->addScriptDeclaration('
- setLayout('edit'); ?> - loadTemplate(); ?> + setLayout('edit'); ?> + loadTemplate(); ?>
diff --git a/src/administrator/components/com_weblinks/tmpl/weblink/modal_associations.php b/src/administrator/components/com_weblinks/tmpl/weblink/modal_associations.php index 731f5d3..4c9be9f 100644 --- a/src/administrator/components/com_weblinks/tmpl/weblink/modal_associations.php +++ b/src/administrator/components/com_weblinks/tmpl/weblink/modal_associations.php @@ -1,4 +1,5 @@ form->getFieldsets('params'); ?> - $fieldSet) : ?> -
- description) && trim($fieldSet->description)) : ?> - ' . $this->escape(Text::_($fieldSet->description)) . '

'; ?> - - form->getFieldset($name) as $field) : ?> -
-
label; ?>
-
input; ?>
-
- -
- + $fieldSet) : + ?> +
+ description) && trim($fieldSet->description)) : + ?> + ' . $this->escape(Text::_($fieldSet->description)) . '

'; ?> + + form->getFieldset($name) as $field) : + ?> +
+
label; ?>
+
input; ?>
+
+ +
+ diff --git a/src/administrator/components/com_weblinks/tmpl/weblinks/default.php b/src/administrator/components/com_weblinks/tmpl/weblinks/default.php index f0a9e62..b423595 100644 --- a/src/administrator/components/com_weblinks/tmpl/weblinks/default.php +++ b/src/administrator/components/com_weblinks/tmpl/weblinks/default.php @@ -1,4 +1,5 @@ getIdentity(); $userId = $user->get('id'); $listOrder = $this->escape($this->state->get('list.ordering')); $listDirn = $this->escape($this->state->get('list.direction')); $saveOrder = $listOrder == 'a.ordering'; $assoc = Associations::isEnabled(); - -if ($saveOrder && !empty($this->items)) -{ - $saveOrderingUrl = 'index.php?option=com_weblinks&task=weblinks.saveOrderAjax&tmpl=component'; - HTMLHelper::_('draggablelist.draggable'); +if ($saveOrder && !empty($this->items)) { + $saveOrderingUrl = 'index.php?option=com_weblinks&task=weblinks.saveOrderAjax&tmpl=component'; + HTMLHelper::_('draggablelist.draggable'); } ?>
-
-
-
- $this]); - ?> - items)) : ?> -
- - -
- - - - - - - - - - - - - - - - - - - - - class="js-draggable" data-url="" data-direction="" data-nested="true"> - items as $i => $item) : ?> - cat_link = Route::_('index.php?option=com_categories&extension=com_weblinks&task=edit&type=other&cid[]=' . $item->catid); ?> - authorise('core.create', 'com_weblinks.category.' . $item->catid); ?> - authorise('core.edit', 'com_weblinks.category.' . $item->catid); ?> - authorise('core.manage', 'com_checkin') || $item->checked_out == $user->id || !$item->checked_out; ?> - authorise('core.edit.own', 'com_weblinks.category.' . $item->catid) && $item->created_by == $user->id; ?> - authorise('core.edit.state', 'com_weblinks.category.' . $item->catid) && $canCheckin; ?> - - - - - - - - - - - - - - - - - - +
+
+
+ $this]); + ?> + items)) : + ?> +
+ + +
+ + + + + + + + + + + + + + + + + + + + + class="js-draggable" data-url="" data-direction="" data-nested="true"> + items as $i => $item) : + ?> + cat_link = Route::_('index.php?option=com_categories&extension=com_weblinks&task=edit&type=other&cid[]=' . $item->catid); ?> + authorise('core.create', 'com_weblinks.category.' . $item->catid); ?> + authorise('core.edit', 'com_weblinks.category.' . $item->catid); ?> + authorise('core.manage', 'com_checkin') || $item->checked_out == $user->id || !$item->checked_out; ?> + authorise('core.edit.own', 'com_weblinks.category.' . $item->catid) && $item->created_by == $user->id; ?> + authorise('core.edit.state', 'com_weblinks.category.' . $item->catid) && $canCheckin; ?> + + + + + + + + + + + + + + + + + + - - pagination->getListFooter(); ?> + + pagination->getListFooter(); ?> - - authorise('core.create', 'com_weblinks') - && $user->authorise('core.edit', 'com_weblinks') - && $user->authorise('core.edit.state', 'com_weblinks')) : ?> - Text::_('COM_WEBLINKS_BATCH_OPTIONS'), - 'footer' => $this->loadTemplate('batch_footer') - ], - $this->loadTemplate('batch_body') - ); ?> - - + + authorise('core.create', 'com_weblinks') + && $user->authorise('core.edit', 'com_weblinks') + && $user->authorise('core.edit.state', 'com_weblinks') +) : + ?> + Text::_('COM_WEBLINKS_BATCH_OPTIONS'), + 'footer' => $this->loadTemplate('batch_footer') + ], $this->loadTemplate('batch_body')); ?> + + - - - -
-
-
+ + + +
+
+
diff --git a/src/administrator/components/com_weblinks/tmpl/weblinks/default_batch_body.php b/src/administrator/components/com_weblinks/tmpl/weblinks/default_batch_body.php index 6b5dab6..e0f8e31 100644 --- a/src/administrator/components/com_weblinks/tmpl/weblinks/default_batch_body.php +++ b/src/administrator/components/com_weblinks/tmpl/weblinks/default_batch_body.php @@ -1,4 +1,5 @@ state->get('filter.published'); ?>
-
- -
-
- -
-
- -
-
- -
-
-
-
- = 0) : ?> -
-
- 'com_weblinks']); ?> -
-
- -
-
- -
-
-
+
+ +
+
+ +
+
+ +
+
+ +
+
+
+
+ = 0) : + ?> +
+
+ 'com_weblinks']); ?> +
+
+ +
+
+ +
+
+
diff --git a/src/administrator/components/com_weblinks/tmpl/weblinks/default_batch_footer.php b/src/administrator/components/com_weblinks/tmpl/weblinks/default_batch_footer.php index 05744dc..51fcc78 100644 --- a/src/administrator/components/com_weblinks/tmpl/weblinks/default_batch_footer.php +++ b/src/administrator/components/com_weblinks/tmpl/weblinks/default_batch_footer.php @@ -1,4 +1,5 @@ diff --git a/src/administrator/components/com_weblinks/tmpl/weblinks/emptystate.php b/src/administrator/components/com_weblinks/tmpl/weblinks/emptystate.php index 8091dd2..5820930 100644 --- a/src/administrator/components/com_weblinks/tmpl/weblinks/emptystate.php +++ b/src/administrator/components/com_weblinks/tmpl/weblinks/emptystate.php @@ -1,4 +1,5 @@ 'COM_WEBLINKS', - 'formURL' => 'index.php?option=com_weblinks', - 'helpURL' => 'https://docs.joomla.org/Special:MyLanguage/Help4.x:Weblinks', - 'icon' => 'icon-globe weblink', + 'textPrefix' => 'COM_WEBLINKS', + 'formURL' => 'index.php?option=com_weblinks', + 'helpURL' => 'https://docs.joomla.org/Special:MyLanguage/Help4.x:Weblinks', + 'icon' => 'icon-globe weblink', ]; - $user = Factory::getApplication()->getIdentity(); - -if ($user->authorise('core.create', 'com_weblinks') || count($user->getAuthorisedCategories('com_weblinks', 'core.create')) > 0) -{ - $displayData['createURL'] = 'index.php?option=com_weblinks&task=weblink.add'; +if ($user->authorise('core.create', 'com_weblinks') || count($user->getAuthorisedCategories('com_weblinks', 'core.create')) > 0) { + $displayData['createURL'] = 'index.php?option=com_weblinks&task=weblink.add'; } -echo LayoutHelper::render('joomla.content.emptystate', $displayData); \ No newline at end of file +echo LayoutHelper::render('joomla.content.emptystate', $displayData); diff --git a/src/administrator/components/com_weblinks/tmpl/weblinks/modal.php b/src/administrator/components/com_weblinks/tmpl/weblinks/modal.php index 05081f4..82c76d9 100644 --- a/src/administrator/components/com_weblinks/tmpl/weblinks/modal.php +++ b/src/administrator/components/com_weblinks/tmpl/weblinks/modal.php @@ -1,4 +1,5 @@ isClient('site')) -{ - Session::checkToken('get') or die(Text::_('JINVALID_TOKEN')); +if ($app->isClient('site')) { + Session::checkToken('get') or die(Text::_('JINVALID_TOKEN')); } HTMLHelper::_('behavior.multiselect'); - $this->document->getWebAssetManager() - ->registerAndUseScript('com_weblinks.admin-weblinks-modal', 'media/com_weblinks/js/admin-weblinks-modal.js', [], ['defer' => true], ['core']); - + ->registerAndUseScript('com_weblinks.admin-weblinks-modal', 'media/com_weblinks/js/admin-weblinks-modal.js', [], ['defer' => true], ['core']); $function = $app->input->getCmd('function', 'jSelectWeblink'); $editor = $app->input->getCmd('editor', ''); $listOrder = $this->escape($this->state->get('list.ordering')); $listDirn = $this->escape($this->state->get('list.direction')); $onclick = $this->escape($function); $multilang = Multilanguage::isEnabled(); - -if (!empty($editor)) -{ - // This view is used also in com_menus. Load the xtd script only if the editor is set! - $this->document->addScriptOptions('xtd-weblinks', array('editor' => $editor)); - $onclick = "jSelectWeblink"; +if (!empty($editor)) { +// This view is used also in com_menus. Load the xtd script only if the editor is set! + $this->document->addScriptOptions('xtd-weblinks', array('editor' => $editor)); + $onclick = "jSelectWeblink"; } $iconStates = array( - -2 => 'icon-trash', - 0 => 'icon-unpublish', - 1 => 'icon-publish', - 2 => 'icon-archive', + -2 => 'icon-trash', + 0 => 'icon-unpublish', + 1 => 'icon-publish', + 2 => 'icon-archive', ); ?>
-
+ - $this)); ?> + $this)); ?> - items)) : ?> -
- -
- - - - - - - - - - - - - - - - - items as $i => $item) : ?> - - language && $multilang) : ?> - language); ?> - - language, 0, 2); ?> - - language, 0, 3); ?> - - - - - - - - - - - - - - -
- , - , - -
- - - - - - - - - - - -
- - - escape($onclick) . '"' - . ' data-id="' . $item->id . '"' - . ' data-title="' . $this->escape(addslashes($item->title)) . '"' - . ' data-cat-id="' . $this->escape($item->catid) . '"' - . ' data-uri="' . $this->escape(RouteHelper::getWeblinkRoute($item->id, $item->catid, $item->language)) . '"' - . ' data-language="' . $this->escape($lang) . '"'; - ?> - > - escape($item->title); ?> - -
- escape($item->category_title); ?> -
-
- escape($item->access_level); ?> - - - - created, Text::_('DATE_FORMAT_LC4')); ?> - - id; ?> -
- + items)) : + ?> +
+ +
+ + + + + + + + + + + + + + + + + items as $i => $item) : + ?> + + language && $multilang) : + ?> + language); ?> + + language, 0, 2); ?> + + language, 0, 3); ?> + + + + + + + + + + + + + + +
+ , + , + +
+ + + + + + + + + + + +
+ + + escape($onclick) . '"' + . ' data-id="' . $item->id . '"' + . ' data-title="' . $this->escape(addslashes($item->title)) . '"' + . ' data-cat-id="' . $this->escape($item->catid) . '"' + . ' data-uri="' . $this->escape(RouteHelper::getWeblinkRoute($item->id, $item->catid, $item->language)) . '"' + . ' data-language="' . $this->escape($lang) . '"'; + ?> + > + escape($item->title); ?> + +
+ escape($item->category_title); ?> +
+
+ escape($item->access_level); ?> + + + + created, Text::_('DATE_FORMAT_LC4')); ?> + + id; ?> +
+ - - pagination->getListFooter(); ?> + + pagination->getListFooter(); ?> - - - - + + + + -
+
diff --git a/src/administrator/components/com_weblinks/weblinks.xml b/src/administrator/components/com_weblinks/weblinks.xml index e36615c..f0f995e 100644 --- a/src/administrator/components/com_weblinks/weblinks.xml +++ b/src/administrator/components/com_weblinks/weblinks.xml @@ -1,68 +1,69 @@ - - - com_weblinks - Joomla! Project - ##DATE## - (C) 2005 - ##YEAR## Open Source Matters. All rights reserved. - GNU General Public License version 2 or later; see LICENSE.txt - admin@joomla.org - www.joomla.org - ##VERSION## - COM_WEBLINKS_XML_DESCRIPTION - script.php - Joomla\Component\Weblinks - - - - sql/install.mysql.sql - sql/install.postgresql.sql - - - - - sql/uninstall.mysql.sql - sql/uninstall.postgresql.sql - - - - - sql/updates/mysql - sql/updates/postgresql - - - - - ##MEDIA_FILES## - - - - ##FRONTEND_COMPONENT_FILES## - - - ##FRONTEND_LANGUAGE_FILES## - - - com_weblinks - - - com_weblinks_links - com_weblinks_categories - com_weblinks_fields - com_weblinks_field_groups - - - ##BACKEND_COMPONENT_FILES## - - - ##BACKEND_LANGUAGE_FILES## - - - - + + + com_weblinks + com_weblinks + Joomla! Project + ##DATE## + (C) 2005 - ##YEAR## Open Source Matters. All rights reserved. + GNU General Public License version 2 or later; see LICENSE.txt + admin@joomla.org + www.joomla.org + ##VERSION## + COM_WEBLINKS_XML_DESCRIPTION + script.php + Joomla\Component\Weblinks + + + + sql/install.mysql.sql + sql/install.postgresql.sql + + + + + sql/uninstall.mysql.sql + sql/uninstall.postgresql.sql + + + + + sql/updates/mysql + sql/updates/postgresql + + + + + ##MEDIA_FILES## + + + + ##FRONTEND_COMPONENT_FILES## + + + ##FRONTEND_LANGUAGE_FILES## + + + com_weblinks + + + com_weblinks_links + com_weblinks_categories + com_weblinks_fields + com_weblinks_field_groups + + + ##BACKEND_COMPONENT_FILES## + + + ##BACKEND_LANGUAGE_FILES## + + + + diff --git a/src/administrator/manifests/packages/weblinks/script.php b/src/administrator/manifests/packages/weblinks/script.php index e9a8179..99ab66a 100644 --- a/src/administrator/manifests/packages/weblinks/script.php +++ b/src/administrator/manifests/packages/weblinks/script.php @@ -1,4 +1,5 @@ minimumJoomla = '3.6.3'; - $this->minimumPhp = JOOMLA_MINIMUM_PHP; - } + /** + * Extension script constructor. + * + * @since __DEPLOY_VERSION__ + */ + public function __construct() + { + $this->minimumJoomla = '3.6.3'; + $this->minimumPhp = JOOMLA_MINIMUM_PHP; + } } diff --git a/src/components/com_weblinks/helpers/icon.php b/src/components/com_weblinks/helpers/icon.php index 6150446..567974d 100644 --- a/src/components/com_weblinks/helpers/icon.php +++ b/src/components/com_weblinks/helpers/icon.php @@ -1,4 +1,5 @@ create($category, $params); - } + /** + * Create a link to create a new weblink + * + * @param object $category The category information + * @param \Joomla\Registry\Registry $params The item parameters + * + * @return string + */ + public static function create($category, $params) + { + return self::getIcon()->create($category, $params); + } - /** - * Create a link to edit an existing weblink - * - * @param object $weblink Weblink data - * @param \Joomla\Registry\Registry $params Item params - * @param array $attribs Unused - * - * @return string - */ - public static function edit($weblink, $params, $attribs = array()) - { - return self::getIcon()->edit($weblink, $params, $attribs); - } + /** + * Create a link to edit an existing weblink + * + * @param object $weblink Weblink data + * @param \Joomla\Registry\Registry $params Item params + * @param array $attribs Unused + * + * @return string + */ + public static function edit($weblink, $params, $attribs = []) + { + return self::getIcon()->edit($weblink, $params, $attribs); + } - /** - * Creates an icon instance. - * - * @return \Joomla\Component\Weblinks\Administrator\Service\HTML\Icon - */ - private static function getIcon() - { - return (new \Joomla\Component\Weblinks\Administrator\Service\HTML\Icon(Joomla\CMS\Factory::getApplication())); - } + /** + * Creates an icon instance. + * + * @return \Joomla\Component\Weblinks\Administrator\Service\HTML\Icon + */ + private static function getIcon() + { + return (new \Joomla\Component\Weblinks\Administrator\Service\HTML\Icon(Joomla\CMS\Factory::getApplication())); + } } diff --git a/src/components/com_weblinks/helpers/route.php b/src/components/com_weblinks/helpers/route.php index c239da3..432bcc3 100644 --- a/src/components/com_weblinks/helpers/route.php +++ b/src/components/com_weblinks/helpers/route.php @@ -1,4 +1,5 @@ input->getInt('w_id'); + $vName = $this->input->get('view', 'categories'); + $this->input->set('view', $vName); + if ($this->app->getIdentity()->id || ($this->input->getMethod() == 'POST' && $vName == 'categories')) { + $cacheable = false; + } - /** - * Set the default view name and format from the Request. - * Note we are using w_id to avoid collisions with the router and the return page. - * Frontend is a bit messier than the backend. - */ - $id = $this->input->getInt('w_id'); - $vName = $this->input->get('view', 'categories'); - $this->input->set('view', $vName); + $safeurlparams = [ + 'id' => 'INT', + 'limit' => 'UINT', + 'limitstart' => 'UINT', + 'filter_order' => 'CMD', + 'filter_order_Dir' => 'CMD', + 'lang' => 'CMD', + ]; + // Check for edit form. + if ($vName == 'form' && !$this->checkEditId('com_weblinks.edit.weblink', $id)) { + // Somehow the person just went to the form - we don't allow that. + throw new \Exception(Text::sprintf('JLIB_APPLICATION_ERROR_UNHELD_ID', $id), 403); + } - if ($this->app->getIdentity()->id ||($this->input->getMethod() == 'POST' && $vName == 'categories')) - { - $cacheable = false; - } - - $safeurlparams = array( - 'id' => 'INT', - 'limit' => 'UINT', - 'limitstart' => 'UINT', - 'filter_order' => 'CMD', - 'filter_order_Dir' => 'CMD', - 'lang' => 'CMD' - ); - - // Check for edit form. - if ($vName == 'form' && !$this->checkEditId('com_weblinks.edit.weblink', $id)) - { - // Somehow the person just went to the form - we don't allow that. - throw new \Exception(Text::sprintf('JLIB_APPLICATION_ERROR_UNHELD_ID', $id), 403); - } - - return parent::display($cacheable, $safeurlparams); - } + return parent::display($cacheable, $safeurlparams); + } } diff --git a/src/components/com_weblinks/src/Controller/WeblinkController.php b/src/components/com_weblinks/src/Controller/WeblinkController.php index 85f0d4f..404829a 100644 --- a/src/components/com_weblinks/src/Controller/WeblinkController.php +++ b/src/components/com_weblinks/src/Controller/WeblinkController.php @@ -1,4 +1,5 @@ setRedirect($this->getReturnPage()); + return false; + } - /** - * The URL view list variable. - * - * @var string - * @since 1.6 - */ - protected $view_list = 'categories'; + return true; + } - /** - * The URL edit variable. - * - * @var string - * @since 3.2 - */ - protected $urlVar = 'a.id'; + /** + * Method override to check if you can add a new record. + * + * @param array $data An array of input data. + * + * @return boolean + * + * @since 1.6 + */ + protected function allowAdd($data = []) + { + $categoryId = ArrayHelper::getValue($data, 'catid', $this->input->getInt('id'), 'int'); + if ($categoryId) { + // If the category has been passed in the URL check it. + return $this->app->getIdentity()->authorise('core.create', $this->option . '.category.' . $categoryId); + } - /** - * Method to add a new record. - * - * @return boolean True if the article can be added, false if not. - * - * @since 1.6 - */ - public function add() - { - if (!parent::add()) - { - // Redirect to the return page. - $this->setRedirect($this->getReturnPage()); + // In the absence of better information, revert to the component permissions. + return parent::allowAdd($data); + } - return false; - } + /** + * Method to check if you can add a new record. + * + * @param array $data An array of input data. + * @param string $key The name of the key for the primary key. + * + * @return boolean + * + * @since 1.6 + */ + protected function allowEdit($data = [], $key = 'id') + { + $recordId = (int) isset($data[$key]) ? $data[$key] : 0; + if (!$recordId) { + return false; + } - return true; - } + $record = $this->getModel()->getItem($recordId); + $categoryId = (int) $record->catid; + if ($categoryId) { + // The category has been set. Check the category permissions. + $user = $this->app->getIdentity(); + // First, check edit permission + if ($user->authorise('core.edit', $this->option . '.category.' . $categoryId)) { + return true; + } - /** - * Method override to check if you can add a new record. - * - * @param array $data An array of input data. - * - * @return boolean - * - * @since 1.6 - */ - protected function allowAdd($data = array()) - { - $categoryId = ArrayHelper::getValue($data, 'catid', $this->input->getInt('id'), 'int'); + // Fallback on edit.own + if ($user->authorise('core.edit.own', $this->option . '.category.' . $categoryId) && $record->created_by == $user->id) { + return true; + } - if ($categoryId) - { - // If the category has been passed in the URL check it. - return $this->app->getIdentity()->authorise('core.create', $this->option . '.category.' . $categoryId); - } + return false; + } - // In the absence of better information, revert to the component permissions. - return parent::allowAdd($data); - } + // Since there is no asset tracking, revert to the component permissions. + return parent::allowEdit($data, $key); + } - /** - * Method to check if you can add a new record. - * - * @param array $data An array of input data. - * @param string $key The name of the key for the primary key. - * - * @return boolean - * - * @since 1.6 - */ - protected function allowEdit($data = array(), $key = 'id') - { - $recordId = (int) isset($data[$key]) ? $data[$key] : 0; + /** + * Method to cancel an edit. + * + * @param string $key The name of the primary key of the URL variable. + * + * @return boolean True if access level checks pass, false otherwise. + * + * @since 1.6 + */ + public function cancel($key = 'w_id') + { + $return = parent::cancel($key); + // Redirect to the return page. + $this->setRedirect($this->getReturnPage()); + return $return; + } - if (!$recordId) - { - return false; - } + /** + * Method to edit an existing record. + * + * @param string $key The name of the primary key of the URL variable. + * @param string $urlVar The name of the URL variable if different from the primary key (sometimes required to avoid router collisions). + * + * @return boolean True if access level check and checkout passes, false otherwise. + * + * @since 1.6 + */ + public function edit($key = null, $urlVar = 'w_id') + { + return parent::edit($key, $urlVar); + } - $record = $this->getModel()->getItem($recordId); - $categoryId = (int) $record->catid; + /** + * Method to get a model object, loading it if required. + * + * @param string $name The model name. Optional. + * @param string $prefix The class prefix. Optional. + * @param array $config Configuration array for model. Optional. + * + * @return object The model. + * + * @since 1.5 + */ + public function getModel($name = 'form', $prefix = 'Site', $config = ['ignore_request' => true]) + { + return parent::getModel($name, $prefix, $config); + } - if ($categoryId) - { - // The category has been set. Check the category permissions. - $user = $this->app->getIdentity(); + /** + * Gets the URL arguments to append to an item redirect. + * + * @param integer $recordId The primary key id for the item. + * @param string $urlVar The name of the URL variable for the id. + * + * @return string The arguments to append to the redirect URL. + * + * @since 1.6 + */ + protected function getRedirectToItemAppend($recordId = null, $urlVar = null) + { + $append = parent::getRedirectToItemAppend($recordId, $urlVar); + $itemId = $this->input->getInt('Itemid'); + $return = $this->getReturnPage(); + if ($itemId) { + $append .= '&Itemid=' . $itemId; + } - // First, check edit permission - if ($user->authorise('core.edit', $this->option . '.category.' . $categoryId)) - { - return true; - } + if ($return) { + $append .= '&return=' . base64_encode($return); + } - // Fallback on edit.own - if ($user->authorise('core.edit.own', $this->option . '.category.' . $categoryId) && $record->created_by == $user->id) - { - return true; - } + return $append; + } - return false; - } + /** + * Get the return URL if a "return" variable has been passed in the request + * + * @return string The return URL. + * + * @since 1.6 + */ + protected function getReturnPage() + { + $return = $this->input->get('return', null, 'base64'); + if (empty($return) || !Uri::isInternal(base64_decode($return))) { + return Uri::base(); + } - // Since there is no asset tracking, revert to the component permissions. - return parent::allowEdit($data, $key); - } + return base64_decode($return); + } - /** - * Method to cancel an edit. - * - * @param string $key The name of the primary key of the URL variable. - * - * @return boolean True if access level checks pass, false otherwise. - * - * @since 1.6 - */ - public function cancel($key = 'w_id') - { - $return = parent::cancel($key); + /** + * Method to save a record. + * + * @param string $key The name of the primary key of the URL variable. + * @param string $urlVar The name of the URL variable if different from the primary key (sometimes required to avoid router collisions). + * + * @return boolean True if successful, false otherwise. + * + * @since 1.6 + */ + public function save($key = null, $urlVar = 'w_id') + { + // Get the application + $app = $this->app; + // Get the data from POST + $data = $this->input->post->get('jform', [], 'array'); + // Save the data in the session. + $app->setUserState('com_weblinks.edit.weblink.data', $data); + $result = parent::save($key, $urlVar); + // If ok, redirect to the return page. + if ($result) { + // Flush the data from the session + $app->setUserState('com_weblinks.edit.weblink.data', null); + $this->setRedirect($this->getReturnPage()); + } - // Redirect to the return page. - $this->setRedirect($this->getReturnPage()); + return $result; + } - return $return; - } + /** + * Go to a weblink + * + * @return void + * + * @throws \Exception + * + * @since 1.6 + */ + public function go() + { + // Get the ID from the request + $id = $this->input->getInt('id'); + // Get the model, requiring published items + $modelLink = $this->getModel('Weblink'); + $modelLink->setState('filter.published', 1); + // Get the item + $link = $modelLink->getItem($id); + // Make sure the item was found. + if (empty($link)) { + throw new \Exception(Text::_('COM_WEBLINKS_ERROR_WEBLINK_NOT_FOUND'), 404); + } - /** - * Method to edit an existing record. - * - * @param string $key The name of the primary key of the URL variable. - * @param string $urlVar The name of the URL variable if different from the primary key (sometimes required to avoid router collisions). - * - * @return boolean True if access level check and checkout passes, false otherwise. - * - * @since 1.6 - */ - public function edit($key = null, $urlVar = 'w_id') - { - return parent::edit($key, $urlVar); - } + // Check whether item access level allows access. + $groups = $this->app->getIdentity()->getAuthorisedViewLevels(); + if (!in_array($link->access, $groups)) { + throw new \Exception(Text::_('JERROR_ALERTNOAUTHOR'), 403); + } - /** - * Method to get a model object, loading it if required. - * - * @param string $name The model name. Optional. - * @param string $prefix The class prefix. Optional. - * @param array $config Configuration array for model. Optional. - * - * @return object The model. - * - * @since 1.5 - */ - public function getModel($name = 'form', $prefix = 'Site', $config = array('ignore_request' => true)) - { - return parent::getModel($name, $prefix, $config); - } + // Check whether category access level allows access. + $modelCat = $this->getModel('Category', 'Site', ['ignore_request' => true]); + $modelCat->setState('filter.published', 1); + // Get the category + $category = $modelCat->getCategory($link->catid); + // Make sure the category was found. + if (empty($category)) { + throw new \Exception(Text::_('COM_WEBLINKS_ERROR_WEBLINK_NOT_FOUND'), 404); + } - /** - * Gets the URL arguments to append to an item redirect. - * - * @param integer $recordId The primary key id for the item. - * @param string $urlVar The name of the URL variable for the id. - * - * @return string The arguments to append to the redirect URL. - * - * @since 1.6 - */ - protected function getRedirectToItemAppend($recordId = null, $urlVar = null) - { - $append = parent::getRedirectToItemAppend($recordId, $urlVar); - $itemId = $this->input->getInt('Itemid'); - $return = $this->getReturnPage(); + // Check whether item access level allows access. + if (!in_array($category->access, $groups)) { + throw new \Exception(Text::_('JERROR_ALERTNOAUTHOR'), 403); + } - if ($itemId) - { - $append .= '&Itemid=' . $itemId; - } + // Redirect to the URL + if ($link->url) { + $modelLink->hit($id); + $this->app->redirect($link->url, 301); + } - if ($return) - { - $append .= '&return=' . base64_encode($return); - } - - return $append; - } - - /** - * Get the return URL if a "return" variable has been passed in the request - * - * @return string The return URL. - * - * @since 1.6 - */ - protected function getReturnPage() - { - $return = $this->input->get('return', null, 'base64'); - - if (empty($return) || !Uri::isInternal(base64_decode($return))) - { - return Uri::base(); - } - - return base64_decode($return); - } - - /** - * Method to save a record. - * - * @param string $key The name of the primary key of the URL variable. - * @param string $urlVar The name of the URL variable if different from the primary key (sometimes required to avoid router collisions). - * - * @return boolean True if successful, false otherwise. - * - * @since 1.6 - */ - public function save($key = null, $urlVar = 'w_id') - { - // Get the application - $app = $this->app; - - // Get the data from POST - $data = $this->input->post->get('jform', array(), 'array'); - - // Save the data in the session. - $app->setUserState('com_weblinks.edit.weblink.data', $data); - $result = parent::save($key, $urlVar); - - // If ok, redirect to the return page. - if ($result) - { - // Flush the data from the session - $app->setUserState('com_weblinks.edit.weblink.data', null); - $this->setRedirect($this->getReturnPage()); - } - - return $result; - } - - /** - * Go to a weblink - * - * @return void - * - * @throws \Exception - * - * @since 1.6 - */ - public function go() - { - // Get the ID from the request - $id = $this->input->getInt('id'); - - // Get the model, requiring published items - $modelLink = $this->getModel('Weblink'); - $modelLink->setState('filter.published', 1); - - // Get the item - $link = $modelLink->getItem($id); - - // Make sure the item was found. - if (empty($link)) - { - throw new \Exception(Text::_('COM_WEBLINKS_ERROR_WEBLINK_NOT_FOUND'), 404); - } - - // Check whether item access level allows access. - $groups = $this->app->getIdentity()->getAuthorisedViewLevels(); - - if (!in_array($link->access, $groups)) - { - throw new \Exception(Text::_('JERROR_ALERTNOAUTHOR'), 403); - } - - // Check whether category access level allows access. - $modelCat = $this->getModel('Category', 'Site', array('ignore_request' => true)); - $modelCat->setState('filter.published', 1); - - // Get the category - $category = $modelCat->getCategory($link->catid); - - // Make sure the category was found. - if (empty($category)) - { - throw new \Exception(Text::_('COM_WEBLINKS_ERROR_WEBLINK_NOT_FOUND'), 404); - } - - // Check whether item access level allows access. - if (!in_array($category->access, $groups)) - { - throw new \Exception(Text::_('JERROR_ALERTNOAUTHOR'), 403); - } - - // Redirect to the URL - if ($link->url) - { - $modelLink->hit($id); - $this->app->redirect($link->url, 301); - } - - throw new \Exception(Text::_('COM_WEBLINKS_ERROR_WEBLINK_URL_INVALID'), 404); - } + throw new \Exception(Text::_('COM_WEBLINKS_ERROR_WEBLINK_URL_INVALID'), 404); + } } diff --git a/src/components/com_weblinks/src/Helper/AssociationHelper.php b/src/components/com_weblinks/src/Helper/AssociationHelper.php index 279bc37..6f73064 100644 --- a/src/components/com_weblinks/src/Helper/AssociationHelper.php +++ b/src/components/com_weblinks/src/Helper/AssociationHelper.php @@ -1,4 +1,5 @@ input; - $view = is_null($view) ? $input->get('view') : $view; - $id = empty($id) ? $input->getInt('id') : $id; + /** + * Method to get the associations for a given item + * + * @param integer $id Id of the item + * @param string $view Name of the view + * + * @return array Array of associations for the item + * + * @since 3.0 + */ + public static function getAssociations($id = 0, $view = null) + { + $input = Factory::getApplication()->input; + $view = is_null($view) ? $input->get('view') : $view; + $id = empty($id) ? $input->getInt('id') : $id; + if ($view === 'weblink') { + if ($id) { + $associations = Associations::getAssociations('com_weblinks', '#__weblinks', 'com_weblinks.item', $id); + $return = []; + foreach ($associations as $tag => $item) { + $return[$tag] = RouteHelper::getWeblinkRoute($item->id, (int) $item->catid, $item->language); + } - if ($view === 'weblink') - { - if ($id) - { - $associations = Associations::getAssociations('com_weblinks', '#__weblinks', 'com_weblinks.item', $id); + return $return; + } + } - $return = array(); + if ($view == 'category' || $view == 'categories') { + return self::getCategoryAssociations($id, 'com_weblinks'); + } - foreach ($associations as $tag => $item) - { - $return[$tag] = RouteHelper::getWeblinkRoute($item->id, (int) $item->catid, $item->language); - } - - return $return; - } - } - - if ($view == 'category' || $view == 'categories') - { - return self::getCategoryAssociations($id, 'com_weblinks'); - } - - return array(); - } + return []; + } } diff --git a/src/components/com_weblinks/src/Helper/RouteHelper.php b/src/components/com_weblinks/src/Helper/RouteHelper.php index c85a2a2..f3b4cfa 100644 --- a/src/components/com_weblinks/src/Helper/RouteHelper.php +++ b/src/components/com_weblinks/src/Helper/RouteHelper.php @@ -1,4 +1,5 @@ 1) { + $link .= '&catid=' . $catid; + } - if ($catid > 1) - { - $link .= '&catid=' . $catid; - } + if ($language && $language !== '*' && Multilanguage::isEnabled()) { + $link .= '&lang=' . $language; + } - if ($language && $language !== '*' && Multilanguage::isEnabled()) - { - $link .= '&lang=' . $language; - } + return $link; + } - return $link; - } + /** + * Ge the form route + * + * @param integer $id The id of the weblink. + * @param string $return The return page variable. + * + * @return string + */ + public static function getFormRoute($id, $return = null) + { + // Create the link. + if ($id) { + $link = 'index.php?option=com_weblinks&task=weblink.edit&w_id=' . $id; + } else { + $link = 'index.php?option=com_weblinks&task=weblink.add&w_id=0'; + } - /** - * Ge the form route - * - * @param integer $id The id of the weblink. - * @param string $return The return page variable. - * - * @return string - */ - public static function getFormRoute($id, $return = null) - { - // Create the link. - if ($id) - { - $link = 'index.php?option=com_weblinks&task=weblink.edit&w_id=' . $id; - } - else - { - $link = 'index.php?option=com_weblinks&task=weblink.add&w_id=0'; - } + if ($return) { + $link .= '&return=' . $return; + } - if ($return) - { - $link .= '&return=' . $return; - } + return $link; + } - return $link; - } + /** + * Get the Category Route + * + * @param CategoryNode|string|integer $catid JCategoryNode object or category ID + * @param integer $language Language code + * + * @return string + */ + public static function getCategoryRoute($catid, $language = 0) + { + if ($catid instanceof CategoryNode) { + $id = $catid->id; + } else { + $id = (int) $catid; + } - /** - * Get the Category Route - * - * @param CategoryNode|string|integer $catid JCategoryNode object or category ID - * @param integer $language Language code - * - * @return string - */ - public static function getCategoryRoute($catid, $language = 0) - { - if ($catid instanceof CategoryNode) - { - $id = $catid->id; - } - else - { - $id = (int) $catid; - } + if ($id < 1) { + $link = ''; + } else { + // Create the link + $link = 'index.php?option=com_weblinks&view=category&id=' . $id; + if ($language && $language !== '*' && Multilanguage::isEnabled()) { + $link .= '&lang=' . $language; + } + } - if ($id < 1) - { - $link = ''; - } - else - { - // Create the link - $link = 'index.php?option=com_weblinks&view=category&id=' . $id; - - if ($language && $language !== '*' && Multilanguage::isEnabled()) - { - $link .= '&lang=' . $language; - } - } - - return $link; - } + return $link; + } } diff --git a/src/components/com_weblinks/src/Model/CategoriesModel.php b/src/components/com_weblinks/src/Model/CategoriesModel.php index a3cc4bf..4744d68 100644 --- a/src/components/com_weblinks/src/Model/CategoriesModel.php +++ b/src/components/com_weblinks/src/Model/CategoriesModel.php @@ -1,4 +1,5 @@ setState('filter.extension', $this->_extension); + // Get the parent id if defined. + $parentId = $app->input->getInt('id'); + $this->setState('filter.parentId', $parentId); + $params = $app->getParams(); + $this->setState('params', $params); + $this->setState('filter.published', 1); + $this->setState('filter.access', true); + } - /** - * The category context (allows other extensions to derived from this model). - * - * @var string - */ - protected $_extension = 'com_weblinks'; + /** + * Method to get a store id based on model configuration state. + * + * This is necessary because the model is used by the component and + * different modules that might need different sets of data or different + * ordering requirements. + * + * @param string $id A prefix for the store id. + * + * @return string A store id. + */ + protected function getStoreId($id = '') + { + // Compile the store id. + $id .= ':' . $this->getState('filter.extension'); + $id .= ':' . $this->getState('filter.published'); + $id .= ':' . $this->getState('filter.access'); + $id .= ':' . $this->getState('filter.parentId'); + return parent::getStoreId($id); + } - /** - * Parent category - * - * @var CategoryNode|null - */ - private $_parent = null; + /** + * Redefine the function and add some properties to make the styling more easy + * + * @return mixed An array of data items on success, false on failure. + */ + public function getItems() + { + if ($this->_items === null) { + $params = $this->getState('params', new Registry()); + $options = []; + $options['access'] = $this->getState('filter.access'); + $options['published'] = $this->getState('filter.published'); + $options['countItems'] = $params->get('show_cat_num_links', 1) || !$params->get('show_empty_categories_cat', 0); + $categories = Categories::getInstance('Weblinks', $options); + $this->_parent = $categories->get($this->getState('filter.parentId', 'root')); + if (is_object($this->_parent)) { + $this->_items = $this->_parent->getChildren(); + } else { + $this->_items = false; + } + } - /** - * Categories data - * - * @var false|array - */ - private $_items = null; + return $this->_items; + } - /** - * Method to auto-populate the model state. - * - * Note. Calling getState in this method will result in recursion. - * - * @param string $ordering An optional ordering field. - * @param string $direction An optional direction (asc|desc). - * - * @return void - * - * @since 1.6 - */ - protected function populateState($ordering = null, $direction = null) - { - $app = Factory::getApplication(); - $this->setState('filter.extension', $this->_extension); + /** + * Get the parent + * + * @return mixed An array of data items on success, false on failure. + */ + public function getParent() + { + if (!is_object($this->_parent)) { + $this->getItems(); + } - // Get the parent id if defined. - $parentId = $app->input->getInt('id'); - $this->setState('filter.parentId', $parentId); - - $params = $app->getParams(); - $this->setState('params', $params); - - $this->setState('filter.published', 1); - $this->setState('filter.access', true); - } - - /** - * Method to get a store id based on model configuration state. - * - * This is necessary because the model is used by the component and - * different modules that might need different sets of data or different - * ordering requirements. - * - * @param string $id A prefix for the store id. - * - * @return string A store id. - */ - protected function getStoreId($id = '') - { - // Compile the store id. - $id .= ':' . $this->getState('filter.extension'); - $id .= ':' . $this->getState('filter.published'); - $id .= ':' . $this->getState('filter.access'); - $id .= ':' . $this->getState('filter.parentId'); - - return parent::getStoreId($id); - } - - /** - * Redefine the function and add some properties to make the styling more easy - * - * @return mixed An array of data items on success, false on failure. - */ - public function getItems() - { - if ($this->_items === null) - { - $params = $this->getState('params', new Registry); - - $options = array(); - $options['access'] = $this->getState('filter.access'); - $options['published'] = $this->getState('filter.published'); - $options['countItems'] = $params->get('show_cat_num_links', 1) || !$params->get('show_empty_categories_cat', 0); - $categories = Categories::getInstance('Weblinks', $options); - $this->_parent = $categories->get($this->getState('filter.parentId', 'root')); - - if (is_object($this->_parent)) - { - $this->_items = $this->_parent->getChildren(); - } - else - { - $this->_items = false; - } - } - - return $this->_items; - } - - /** - * Get the parent - * - * @return mixed An array of data items on success, false on failure. - */ - public function getParent() - { - if (!is_object($this->_parent)) - { - $this->getItems(); - } - - return $this->_parent; - } + return $this->_parent; + } } diff --git a/src/components/com_weblinks/src/Model/CategoryModel.php b/src/components/com_weblinks/src/Model/CategoryModel.php index 47a2a7d..c17a6e4 100644 --- a/src/components/com_weblinks/src/Model/CategoryModel.php +++ b/src/components/com_weblinks/src/Model/CategoryModel.php @@ -1,4 +1,5 @@ _params)) - { - $item->params = new Registry($item->params); - } - - // Some contexts may not use tags data at all, so we allow callers to disable loading tag data - if ($this->getState('load_tags', true)) - { - $item->tags = new TagsHelper; - $taggedItems[$item->id] = $item; - } - } - - // Load tags of all items. - if ($taggedItems) - { - $tagsHelper = new TagsHelper(); - $itemIds = \array_keys($taggedItems); - - foreach ($tagsHelper->getMultipleItemTags('com_weblinks.weblink', $itemIds) as $id => $tags) - { - $taggedItems[$id]->tags->itemTags = $tags; - } - } - - return $items; - } - - /** - * Method to get a JDatabaseQuery object for retrieving the data set from a database. - * - * @return \JDatabaseQuery A JDatabaseQuery object to retrieve the data set. - * - * @since 1.6 - */ - protected function getListQuery() - { - $viewLevels = $this->getCurrentUser()->getAuthorisedViewLevels(); - - // Create a new query object. - $db = $this->getDatabase(); - $query = $db->getQuery(true); - - // Select required fields from the categories. - $query->select($this->getState('list.select', 'a.*')) - ->from($db->quoteName('#__weblinks') . ' AS a') - ->whereIn($db->quoteName('a.access'), $viewLevels); - - // Filter by category. - if ($categoryId = $this->getState('category.id')) - { - // Group by subcategory - if ($this->getState('category.group', 0)) - { - $query->select('c.title AS category_title') - ->where('c.parent_id = :parent_id') - ->bind(':parent_id', $categoryId, ParameterType::INTEGER) - ->join('LEFT', '#__categories AS c ON c.id = a.catid') - ->whereIn($db->quoteName('c.access'), $viewLevels); - } - else - { - $query->where('a.catid = :catid') - ->bind(':catid', $categoryId, ParameterType::INTEGER) - ->join('LEFT', '#__categories AS c ON c.id = a.catid') - ->whereIn($db->quoteName('c.access'), $viewLevels); - } - - // Filter by published category - $cpublished = $this->getState('filter.c.published'); - - if (is_numeric($cpublished)) - { - $query->where('c.published = :published') - ->bind(':published', $cpublished, ParameterType::INTEGER); - } - } - - // Join over the users for the author and modified_by names. - $query->select("CASE WHEN a.created_by_alias > ' ' THEN a.created_by_alias ELSE ua.name END AS author") - ->select("ua.email AS author_email") - ->join('LEFT', '#__users AS ua ON ua.id = a.created_by') - ->join('LEFT', '#__users AS uam ON uam.id = a.modified_by'); - - // Filter by state - $state = $this->getState('filter.state'); - - if (is_numeric($state)) - { - $query->where('a.state = :state') - ->bind(':state', $state, ParameterType::INTEGER); - } - - // Do not show trashed links on the front-end - $query->where('a.state != -2'); - - // Filter by start and end dates. - if ($this->getState('filter.publish_date')) - { - $nowDate = Factory::getDate()->toSql(); - $query->where('(' . $db->quoteName('a.publish_up') - . ' IS NULL OR ' . $db->quoteName('a.publish_up') . ' <= :publish_up)' - ) - ->where('(' . $db->quoteName('a.publish_down') - . ' IS NULL OR ' . $db->quoteName('a.publish_down') . ' >= :publish_down)' - ) - ->bind(':publish_up', $nowDate) - ->bind(':publish_down', $nowDate); - } - - // Filter by language - if ($this->getState('filter.language')) - { - $query->whereIn($db->quoteName('a.language'), [Factory::getLanguage()->getTag(), '*'], ParameterType::STRING); - } - - // Filter by search in title - $search = $this->getState('list.filter'); - - if (!empty($search)) - { - $search = '%' . trim($search) . '%'; - $query->where('(a.title LIKE :search)') - ->bind(':search', $search); - } - - // If grouping by subcategory, add the subcategory list ordering clause. - if ($this->getState('category.group', 0)) - { - $query->order( - $db->escape($this->getState('category.ordering', 'c.lft')) . ' ' . - $db->escape($this->getState('category.direction', 'ASC')) - ); - } - - // Add the list ordering clause. - $query->order( - $db->escape($this->getState('list.ordering', 'a.ordering')) . ' ' . - $db->escape($this->getState('list.direction', 'ASC')) - ); - - return $query; - } - - /** - * Method to auto-populate the model state. - * - * Note. Calling getState in this method will result in recursion. - * - * @param string $ordering An optional ordering field. - * @param string $direction An optional direction (asc|desc). - * - * @return void - * - * @since 1.6 - */ - protected function populateState($ordering = null, $direction = null) - { - $app = Factory::getApplication(); - - $params = $app->getParams(); - $this->setState('params', $params); - - // List state information - $limit = $app->getUserStateFromRequest('global.list.limit', 'limit', $app->get('list_limit'), 'uint'); - $this->setState('list.limit', $limit); - - $limitstart = $app->input->get('limitstart', 0, 'uint'); - $this->setState('list.start', $limitstart); - - // Optional filter text - $this->setState('list.filter', $app->input->getString('filter-search')); - - $orderCol = $app->input->get('filter_order', 'ordering'); - - if (!in_array($orderCol, $this->filter_fields)) - { - $orderCol = 'ordering'; - } - - $this->setState('list.ordering', $orderCol); - - $listOrder = $app->input->get('filter_order_Dir', 'ASC'); - - if (!in_array(strtoupper($listOrder), array('ASC', 'DESC', ''))) - { - $listOrder = 'ASC'; - } - - $this->setState('list.direction', $listOrder); - - $id = $app->input->get('id', 0, 'int'); - $this->setState('category.id', $id); - - $user = $this->getCurrentUser(); - - if (!$user->authorise('core.edit.state', 'com_weblinks') && !$user->authorise('core.edit', 'com_weblinks')) - { - // Limit to published for people who can't edit or edit.state. - $this->setState('filter.state', 1); - - // Filter by start and end dates. - $this->setState('filter.publish_date', true); - } - - $this->setState('filter.language', Multilanguage::isEnabled()); - } - - /** - * Method to get category data for the current category - * - * @return object - * - * @since 1.5 - */ - public function getCategory() - { - if (!is_object($this->_item)) - { - $params = $this->getState('params', new Registry); - - $options = array(); - $options['countItems'] = $params->get('show_cat_num_links_cat', 1) - || $params->get('show_empty_categories', 0); - - $categories = Categories::getInstance('Weblinks', $options); - $this->_item = $categories->get($this->getState('category.id', 'root')); - - if (is_object($this->_item)) - { - $this->_children = $this->_item->getChildren(); - $this->_parent = false; - - if ($this->_item->getParent()) - { - $this->_parent = $this->_item->getParent(); - } - - $this->_rightsibling = $this->_item->getSibling(); - $this->_leftsibling = $this->_item->getSibling(false); - } - else - { - $this->_children = false; - $this->_parent = false; - } - } - - return $this->_item; - } - - /** - * Get the parent category - * - * @return mixed An array of categories or false if an error occurs. - */ - public function getParent() - { - if (!is_object($this->_item)) - { - $this->getCategory(); - } - - return $this->_parent; - } - - /** - * Get the leftsibling (adjacent) categories. - * - * @return mixed An array of categories or false if an error occurs. - */ - public function &getLeftSibling() - { - if (!is_object($this->_item)) - { - $this->getCategory(); - } - - return $this->_leftsibling; - } - - /** - * Get the rightsibling (adjacent) categories. - * - * @return mixed An array of categories or false if an error occurs. - */ - public function &getRightSibling() - { - if (!is_object($this->_item)) - { - $this->getCategory(); - } - - return $this->_rightsibling; - } - - /** - * Get the child categories. - * - * @return mixed An array of categories or false if an error occurs. - */ - public function &getChildren() - { - if (!is_object($this->_item)) - { - $this->getCategory(); - } - - return $this->_children; - } - - /** - * Increment the hit counter for the category. - * - * @param integer $pk Optional primary key of the category to increment. - * - * @return boolean True if successful; false otherwise and internal error set. - * - * @since 3.2 - */ - public function hit($pk = 0) - { - $hitcount = Factory::getApplication()->input->getInt('hitcount', 1); - - if ($hitcount) - { - $pk = (!empty($pk)) ? $pk : (int) $this->getState('category.id'); - $table = Table::getInstance('Category', 'Joomla\\CMS\\Table\\'); - $table->load($pk); - $table->hit($pk); - } - - return true; - } + /** + * Category item data + * + * @var CategoryNode|null + */ + protected $_item = null; + + /** + * Category left of this one + * + * @var CategoryNode|null + */ + protected $_leftsibling = null; + + /** + * Category right right of this one + * + * @var CategoryNode|null + */ + protected $_rightsibling = null; + + /** + * Array of child-categories + * + * @var CategoryNode[]|null + */ + protected $_children = null; + + /** + * Parent category of the current one + * + * @var CategoryNode|null + */ + protected $_parent = null; + + /** + * Constructor. + * + * @param array $config An optional associative array of configuration settings. + * + * @see JControllerLegacy + * @since 1.6 + */ + public function __construct($config = []) + { + if (empty($config['filter_fields'])) { + $config['filter_fields'] = [ + 'id', 'a.id', + 'title', 'a.title', + 'hits', 'a.hits', + 'ordering', 'a.ordering', + ]; + } + + parent::__construct($config); + } + + + /** + * Method to get a list of items. + * + * @return mixed An array of objects on success, false on failure. + */ + public function getItems() + { + // Invoke the parent getItems method to get the main list + $items = parent::getItems(); + + $taggedItems = []; + + // Convert the params field into an object, saving original in _params + foreach ($items as $item) { + if (!isset($this->_params)) { + $item->params = new Registry($item->params); + } + + // Some contexts may not use tags data at all, so we allow callers to disable loading tag data + if ($this->getState('load_tags', true)) { + $item->tags = new TagsHelper(); + $taggedItems[$item->id] = $item; + } + } + + // Load tags of all items. + if ($taggedItems) { + $tagsHelper = new TagsHelper(); + $itemIds = \array_keys($taggedItems); + + foreach ($tagsHelper->getMultipleItemTags('com_weblinks.weblink', $itemIds) as $id => $tags) { + $taggedItems[$id]->tags->itemTags = $tags; + } + } + + return $items; + } + + /** + * Method to get a JDatabaseQuery object for retrieving the data set from a database. + * + * @return \JDatabaseQuery A JDatabaseQuery object to retrieve the data set. + * + * @since 1.6 + */ + protected function getListQuery() + { + $viewLevels = $this->getCurrentUser()->getAuthorisedViewLevels(); + + // Create a new query object. + $db = $this->getDatabase(); + $query = $db->getQuery(true); + + // Select required fields from the categories. + $query->select($this->getState('list.select', 'a.*')) + ->from($db->quoteName('#__weblinks') . ' AS a') + ->whereIn($db->quoteName('a.access'), $viewLevels); + + // Filter by category. + if ($categoryId = $this->getState('category.id')) { + // Group by subcategory + if ($this->getState('category.group', 0)) { + $query->select('c.title AS category_title') + ->where('c.parent_id = :parent_id') + ->bind(':parent_id', $categoryId, ParameterType::INTEGER) + ->join('LEFT', '#__categories AS c ON c.id = a.catid') + ->whereIn($db->quoteName('c.access'), $viewLevels); + } else { + $query->where('a.catid = :catid') + ->bind(':catid', $categoryId, ParameterType::INTEGER) + ->join('LEFT', '#__categories AS c ON c.id = a.catid') + ->whereIn($db->quoteName('c.access'), $viewLevels); + } + + // Filter by published category + $cpublished = $this->getState('filter.c.published'); + + if (is_numeric($cpublished)) { + $query->where('c.published = :published') + ->bind(':published', $cpublished, ParameterType::INTEGER); + } + } + + // Join over the users for the author and modified_by names. + $query->select("CASE WHEN a.created_by_alias > ' ' THEN a.created_by_alias ELSE ua.name END AS author") + ->select("ua.email AS author_email") + ->join('LEFT', '#__users AS ua ON ua.id = a.created_by') + ->join('LEFT', '#__users AS uam ON uam.id = a.modified_by'); + + // Filter by state + $state = $this->getState('filter.state'); + + if (is_numeric($state)) { + $query->where('a.state = :state') + ->bind(':state', $state, ParameterType::INTEGER); + } + + // Do not show trashed links on the front-end + $query->where('a.state != -2'); + + // Filter by start and end dates. + if ($this->getState('filter.publish_date')) { + $nowDate = Factory::getDate()->toSql(); + $query->where('(' . $db->quoteName('a.publish_up') + . ' IS NULL OR ' . $db->quoteName('a.publish_up') . ' <= :publish_up)') + ->where('(' . $db->quoteName('a.publish_down') + . ' IS NULL OR ' . $db->quoteName('a.publish_down') . ' >= :publish_down)') + ->bind(':publish_up', $nowDate) + ->bind(':publish_down', $nowDate); + } + + // Filter by language + if ($this->getState('filter.language')) { + $query->whereIn($db->quoteName('a.language'), [Factory::getLanguage()->getTag(), '*'], ParameterType::STRING); + } + + // Filter by search in title + $search = $this->getState('list.filter'); + + if (!empty($search)) { + $search = '%' . trim($search) . '%'; + $query->where('(a.title LIKE :search)') + ->bind(':search', $search); + } + + // If grouping by subcategory, add the subcategory list ordering clause. + if ($this->getState('category.group', 0)) { + $query->order( + $db->escape($this->getState('category.ordering', 'c.lft')) . ' ' . + $db->escape($this->getState('category.direction', 'ASC')) + ); + } + + // Add the list ordering clause. + $query->order( + $db->escape($this->getState('list.ordering', 'a.ordering')) . ' ' . + $db->escape($this->getState('list.direction', 'ASC')) + ); + + return $query; + } + + /** + * Method to auto-populate the model state. + * + * Note. Calling getState in this method will result in recursion. + * + * @param string $ordering An optional ordering field. + * @param string $direction An optional direction (asc|desc). + * + * @return void + * + * @since 1.6 + */ + protected function populateState($ordering = null, $direction = null) + { + $app = Factory::getApplication(); + + $params = $app->getParams(); + $this->setState('params', $params); + + // List state information + $limit = $app->getUserStateFromRequest('global.list.limit', 'limit', $app->get('list_limit'), 'uint'); + $this->setState('list.limit', $limit); + + $limitstart = $app->input->get('limitstart', 0, 'uint'); + $this->setState('list.start', $limitstart); + + // Optional filter text + $this->setState('list.filter', $app->input->getString('filter-search')); + + $orderCol = $app->input->get('filter_order', 'ordering'); + + if (!in_array($orderCol, $this->filter_fields)) { + $orderCol = 'ordering'; + } + + $this->setState('list.ordering', $orderCol); + + $listOrder = $app->input->get('filter_order_Dir', 'ASC'); + + if (!in_array(strtoupper($listOrder), ['ASC', 'DESC', ''])) { + $listOrder = 'ASC'; + } + + $this->setState('list.direction', $listOrder); + + $id = $app->input->get('id', 0, 'int'); + $this->setState('category.id', $id); + + $user = $this->getCurrentUser(); + + if (!$user->authorise('core.edit.state', 'com_weblinks') && !$user->authorise('core.edit', 'com_weblinks')) { + // Limit to published for people who can't edit or edit.state. + $this->setState('filter.state', 1); + + // Filter by start and end dates. + $this->setState('filter.publish_date', true); + } + + $this->setState('filter.language', Multilanguage::isEnabled()); + } + + /** + * Method to get category data for the current category + * + * @return object + * + * @since 1.5 + */ + public function getCategory() + { + if (!is_object($this->_item)) { + $params = $this->getState('params', new Registry()); + + $options = []; + $options['countItems'] = $params->get('show_cat_num_links_cat', 1) + || $params->get('show_empty_categories', 0); + + $categories = Categories::getInstance('Weblinks', $options); + $this->_item = $categories->get($this->getState('category.id', 'root')); + + if (is_object($this->_item)) { + $this->_children = $this->_item->getChildren(); + $this->_parent = false; + + if ($this->_item->getParent()) { + $this->_parent = $this->_item->getParent(); + } + + $this->_rightsibling = $this->_item->getSibling(); + $this->_leftsibling = $this->_item->getSibling(false); + } else { + $this->_children = false; + $this->_parent = false; + } + } + + return $this->_item; + } + + /** + * Get the parent category + * + * @return mixed An array of categories or false if an error occurs. + */ + public function getParent() + { + if (!is_object($this->_item)) { + $this->getCategory(); + } + + return $this->_parent; + } + + /** + * Get the leftsibling (adjacent) categories. + * + * @return mixed An array of categories or false if an error occurs. + */ + public function &getLeftSibling() + { + if (!is_object($this->_item)) { + $this->getCategory(); + } + + return $this->_leftsibling; + } + + /** + * Get the rightsibling (adjacent) categories. + * + * @return mixed An array of categories or false if an error occurs. + */ + public function &getRightSibling() + { + if (!is_object($this->_item)) { + $this->getCategory(); + } + + return $this->_rightsibling; + } + + /** + * Get the child categories. + * + * @return mixed An array of categories or false if an error occurs. + */ + public function &getChildren() + { + if (!is_object($this->_item)) { + $this->getCategory(); + } + + return $this->_children; + } + + /** + * Increment the hit counter for the category. + * + * @param integer $pk Optional primary key of the category to increment. + * + * @return boolean True if successful; false otherwise and internal error set. + * + * @since 3.2 + */ + public function hit($pk = 0) + { + $hitcount = Factory::getApplication()->input->getInt('hitcount', 1); + + if ($hitcount) { + $pk = (!empty($pk)) ? $pk : (int) $this->getState('category.id'); + $table = Table::getInstance('Category', 'Joomla\\CMS\\Table\\'); + $table->load($pk); + $table->hit($pk); + } + + return true; + } } diff --git a/src/components/com_weblinks/src/Model/FormModel.php b/src/components/com_weblinks/src/Model/FormModel.php index 6de943e..c8e1778 100644 --- a/src/components/com_weblinks/src/Model/FormModel.php +++ b/src/components/com_weblinks/src/Model/FormModel.php @@ -1,4 +1,5 @@ getState('return_page', '')); - } + /** + * Get the return URL. + * + * @return string The return URL. + * + * @since 1.6 + */ + public function getReturnPage() + { + return base64_encode($this->getState('return_page', '')); + } - /** - * Method to auto-populate the model state. - * - * Note. Calling getState in this method will result in recursion. - * - * @return void - * - * @since 1.6 - */ - protected function populateState() - { - $app = Factory::getApplication(); + /** + * Method to auto-populate the model state. + * + * Note. Calling getState in this method will result in recursion. + * + * @return void + * + * @since 1.6 + */ + protected function populateState() + { + $app = Factory::getApplication(); - // Load state from the request. - $pk = $app->input->getInt('w_id'); - $this->setState('weblink.id', $pk); + // Load state from the request. + $pk = $app->input->getInt('w_id'); + $this->setState('weblink.id', $pk); - // Add compatibility variable for default naming conventions. - $this->setState('form.id', $pk); + // Add compatibility variable for default naming conventions. + $this->setState('form.id', $pk); - $categoryId = $app->input->getInt('catid'); - $this->setState('weblink.catid', $categoryId); + $categoryId = $app->input->getInt('catid'); + $this->setState('weblink.catid', $categoryId); - $return = $app->input->get('return', '', 'base64'); + $return = $app->input->get('return', '', 'base64'); - if ($return && !Uri::isInternal(base64_decode($return))) - { - $return = ''; - } + if ($return && !Uri::isInternal(base64_decode($return))) { + $return = ''; + } - $this->setState('return_page', base64_decode($return)); + $this->setState('return_page', base64_decode($return)); - // Load the parameters. - $params = $app->getParams(); - $this->setState('params', $params); + // Load the parameters. + $params = $app->getParams(); + $this->setState('params', $params); - $this->setState('layout', $app->input->getString('layout')); - } + $this->setState('layout', $app->input->getString('layout')); + } - /** - * Abstract method for getting the form from the model. - * - * @param array $data Data for the form. - * @param boolean $loadData True if the form is to load its own data (default case), false if not. - * - * @return mixed A JForm object on success, false on failure - * - * @since __DEPLOY_VERSION__ - */ - public function getForm($data = array(), $loadData = true) - { - $form = $this->loadForm('com_weblinks.form', 'weblink', array('control' => 'jform', 'load_data' => $loadData)); + /** + * Abstract method for getting the form from the model. + * + * @param array $data Data for the form. + * @param boolean $loadData True if the form is to load its own data (default case), false if not. + * + * @return mixed A JForm object on success, false on failure + * + * @since __DEPLOY_VERSION__ + */ + public function getForm($data = [], $loadData = true) + { + $form = $this->loadForm('com_weblinks.form', 'weblink', ['control' => 'jform', 'load_data' => $loadData]); - // Disable the buttons and just allow editor none for not authenticated users - if ($this->getCurrentUser()->guest) - { - $form->setFieldAttribute('description', 'editor', 'none'); - $form->setFieldAttribute('description', 'buttons', 'no'); - } + // Disable the buttons and just allow editor none for not authenticated users + if ($this->getCurrentUser()->guest) { + $form->setFieldAttribute('description', 'editor', 'none'); + $form->setFieldAttribute('description', 'buttons', 'no'); + } - return $form; - } + return $form; + } - /** - * Method to get a table object, load it if necessary. - * - * @param string $name The table name. Optional. - * @param string $prefix The class prefix. Optional. - * @param array $options Configuration array for model. Optional. - * - * @return Table A Table object - * - * @since 4.0.0 - * @throws \Exception - */ - public function getTable($name = 'Weblink', $prefix = 'Administrator', $options = array()) - { - return parent::getTable($name, $prefix, $options); - } + /** + * Method to get a table object, load it if necessary. + * + * @param string $name The table name. Optional. + * @param string $prefix The class prefix. Optional. + * @param array $options Configuration array for model. Optional. + * + * @return Table A Table object + * + * @since 4.0.0 + * @throws \Exception + */ + public function getTable($name = 'Weblink', $prefix = 'Administrator', $options = []) + { + return parent::getTable($name, $prefix, $options); + } } diff --git a/src/components/com_weblinks/src/Model/WeblinkModel.php b/src/components/com_weblinks/src/Model/WeblinkModel.php index 959cb5d..82a0733 100644 --- a/src/components/com_weblinks/src/Model/WeblinkModel.php +++ b/src/components/com_weblinks/src/Model/WeblinkModel.php @@ -1,4 +1,5 @@ input->getInt('id'); - $this->setState('weblink.id', $pk); + // Load the object state. + $pk = $app->input->getInt('id'); + $this->setState('weblink.id', $pk); - // Load the parameters. - $params = $app->getParams(); - $this->setState('params', $params); + // Load the parameters. + $params = $app->getParams(); + $this->setState('params', $params); - $user = $this->getCurrentUser(); + $user = $this->getCurrentUser(); - if (!$user->authorise('core.edit.state', 'com_weblinks') && !$user->authorise('core.edit', 'com_weblinks')) - { - $this->setState('filter.published', 1); - $this->setState('filter.archived', 2); - } + if (!$user->authorise('core.edit.state', 'com_weblinks') && !$user->authorise('core.edit', 'com_weblinks')) { + $this->setState('filter.published', 1); + $this->setState('filter.archived', 2); + } - $this->setState('filter.language', Multilanguage::isEnabled()); - } + $this->setState('filter.language', Multilanguage::isEnabled()); + } - /** - * Method to get an object. - * - * @param integer $pk The id of the object to get. - * - * @return mixed Object on success, false on failure. - */ - public function getItem($pk = null) - { - $user = $this->getCurrentUser(); + /** + * Method to get an object. + * + * @param integer $pk The id of the object to get. + * + * @return mixed Object on success, false on failure. + */ + public function getItem($pk = null) + { + $user = $this->getCurrentUser(); - $pk = (!empty($pk)) ? $pk : (int) $this->getState('weblink.id'); + $pk = (!empty($pk)) ? $pk : (int) $this->getState('weblink.id'); - if ($this->_item === null) - { - $this->_item = array(); - } + if ($this->_item === null) { + $this->_item = []; + } - if (!isset($this->_item[$pk])) - { - try - { - $db = $this->getDatabase(); - $query = $db->getQuery(true) - ->select($this->getState('item.select', 'a.*')) - ->from('#__weblinks AS a') - ->where($db->quoteName('a.id') . ' = :id') - ->bind(':id', $pk, ParameterType::INTEGER); + if (!isset($this->_item[$pk])) { + try { + $db = $this->getDatabase(); + $query = $db->getQuery(true) + ->select($this->getState('item.select', 'a.*')) + ->from('#__weblinks AS a') + ->where($db->quoteName('a.id') . ' = :id') + ->bind(':id', $pk, ParameterType::INTEGER); - // Join on category table. - $query->select('c.title AS category_title, c.alias AS category_alias, c.access AS category_access') - ->innerJoin('#__categories AS c on c.id = a.catid') - ->where('c.published > 0'); + // Join on category table. + $query->select('c.title AS category_title, c.alias AS category_alias, c.access AS category_access') + ->innerJoin('#__categories AS c on c.id = a.catid') + ->where('c.published > 0'); - // Join on user table. - $query->select('u.name AS author') - ->join('LEFT', '#__users AS u on u.id = a.created_by'); + // Join on user table. + $query->select('u.name AS author') + ->join('LEFT', '#__users AS u on u.id = a.created_by'); - // Filter by language - if ($this->getState('filter.language')) - { - $query->whereIn($db->quoteName('a.language'), [Factory::getLanguage()->getTag(), '*'], ParameterType::STRING); - } + // Filter by language + if ($this->getState('filter.language')) { + $query->whereIn($db->quoteName('a.language'), [Factory::getLanguage()->getTag(), '*'], ParameterType::STRING); + } - // Join over the categories to get parent category titles - $query->select('parent.title as parent_title, parent.id as parent_id, parent.path as parent_route, parent.alias as parent_alias') - ->join('LEFT', '#__categories as parent ON parent.id = c.parent_id'); + // Join over the categories to get parent category titles + $query->select('parent.title as parent_title, parent.id as parent_id, parent.path as parent_route, parent.alias as parent_alias') + ->join('LEFT', '#__categories as parent ON parent.id = c.parent_id'); - if (!$user->authorise('core.edit.state', 'com_weblinks') && !$user->authorise('core.edit', 'com_weblinks')) - { - // Filter by start and end dates. - $nowDate = Factory::getDate()->toSql(); - $query->where('(' . $db->quoteName('a.publish_up') - . ' IS NULL OR ' . $db->quoteName('a.publish_up') . ' <= :publish_up)' - ) - ->where('(' . $db->quoteName('a.publish_down') - . ' IS NULL OR ' . $db->quoteName('a.publish_down') . ' >= :publish_down)' - ) - ->bind(':publish_up', $nowDate) - ->bind(':publish_down', $nowDate); - } + if (!$user->authorise('core.edit.state', 'com_weblinks') && !$user->authorise('core.edit', 'com_weblinks')) { + // Filter by start and end dates. + $nowDate = Factory::getDate()->toSql(); + $query->where('(' . $db->quoteName('a.publish_up') + . ' IS NULL OR ' . $db->quoteName('a.publish_up') . ' <= :publish_up)') + ->where('(' . $db->quoteName('a.publish_down') + . ' IS NULL OR ' . $db->quoteName('a.publish_down') . ' >= :publish_down)') + ->bind(':publish_up', $nowDate) + ->bind(':publish_down', $nowDate); + } - // Filter by published state. - $published = $this->getState('filter.published'); - $archived = $this->getState('filter.archived'); + // Filter by published state. + $published = $this->getState('filter.published'); + $archived = $this->getState('filter.archived'); - if (is_numeric($published)) - { - $query->whereIn($db->quoteName('a.state'), [$published, $archived]); - } + if (is_numeric($published)) { + $query->whereIn($db->quoteName('a.state'), [$published, $archived]); + } - $db->setQuery($query); + $db->setQuery($query); - $data = $db->loadObject(); + $data = $db->loadObject(); - if (empty($data)) - { - throw new \Exception(Text::_('COM_WEBLINKS_ERROR_WEBLINK_NOT_FOUND'), 404); - } + if (empty($data)) { + throw new \Exception(Text::_('COM_WEBLINKS_ERROR_WEBLINK_NOT_FOUND'), 404); + } - // Check for published state if filter set. - if ((is_numeric($published) || is_numeric($archived)) && (($data->state != $published) && ($data->state != $archived))) - { - throw new \Exception(Text::_('COM_WEBLINKS_ERROR_WEBLINK_NOT_FOUND'), 404); - } + // Check for published state if filter set. + if ((is_numeric($published) || is_numeric($archived)) && (($data->state != $published) && ($data->state != $archived))) { + throw new \Exception(Text::_('COM_WEBLINKS_ERROR_WEBLINK_NOT_FOUND'), 404); + } - // Convert parameter fields to objects. - $data->params = new Registry($data->params); - $data->metadata = new Registry($data->metadata); + // Convert parameter fields to objects. + $data->params = new Registry($data->params); + $data->metadata = new Registry($data->metadata); - // Some contexts may not use tags data at all, so we allow callers to disable loading tag data - if ($this->getState('load_tags', true)) - { - $data->tags = new TagsHelper; - $data->tags->getItemTags('com_weblinks.weblink', $data->id); - } + // Some contexts may not use tags data at all, so we allow callers to disable loading tag data + if ($this->getState('load_tags', true)) { + $data->tags = new TagsHelper(); + $data->tags->getItemTags('com_weblinks.weblink', $data->id); + } - // Compute access permissions. - if ($access = $this->getState('filter.access')) - { - // If the access filter has been set, we already know this user can view. - $data->params->set('access-view', true); - } - else - { - // If no access filter is set, the layout takes some responsibility for display of limited information. - $groups = $user->getAuthorisedViewLevels(); - $data->params->set('access-view', in_array($data->access, $groups) && in_array($data->category_access, $groups)); - } + // Compute access permissions. + if ($access = $this->getState('filter.access')) { + // If the access filter has been set, we already know this user can view. + $data->params->set('access-view', true); + } else { + // If no access filter is set, the layout takes some responsibility for display of limited information. + $groups = $user->getAuthorisedViewLevels(); + $data->params->set('access-view', in_array($data->access, $groups) && in_array($data->category_access, $groups)); + } - $this->_item[$pk] = $data; - } - catch (\Exception $e) - { - $this->setError($e); - $this->_item[$pk] = false; - } - } + $this->_item[$pk] = $data; + } catch (\Exception $e) { + $this->setError($e); + $this->_item[$pk] = false; + } + } - return $this->_item[$pk]; - } + return $this->_item[$pk]; + } - /** - * Returns a reference to the a Table object, always creating it. - * - * @param string $type The table type to instantiate - * @param string $prefix A prefix for the table class name. Optional. - * @param array $config Configuration array for model. Optional. - * - * @return Table A database object - * - * @since 1.6 - */ - public function getTable($type = 'Weblink', $prefix = 'Administrator', $config = array()) - { - return parent::getTable($type, $prefix, $config); - } + /** + * Returns a reference to the a Table object, always creating it. + * + * @param string $type The table type to instantiate + * @param string $prefix A prefix for the table class name. Optional. + * @param array $config Configuration array for model. Optional. + * + * @return Table A database object + * + * @since 1.6 + */ + public function getTable($type = 'Weblink', $prefix = 'Administrator', $config = []) + { + return parent::getTable($type, $prefix, $config); + } - /** - * Method to increment the hit counter for the weblink - * - * @param integer $pk Optional ID of the weblink. - * - * @return boolean True on success - */ - public function hit($pk = null) - { - if (empty($pk)) - { - $pk = $this->getState('weblink.id'); - } + /** + * Method to increment the hit counter for the weblink + * + * @param integer $pk Optional ID of the weblink. + * + * @return boolean True on success + */ + public function hit($pk = null) + { + if (empty($pk)) { + $pk = $this->getState('weblink.id'); + } - return $this->getTable('Weblink')->hit($pk); - } + return $this->getTable('Weblink')->hit($pk); + } } diff --git a/src/components/com_weblinks/src/Service/Category.php b/src/components/com_weblinks/src/Service/Category.php index 1c8f1c3..ba82752 100644 --- a/src/components/com_weblinks/src/Service/Category.php +++ b/src/components/com_weblinks/src/Service/Category.php @@ -1,4 +1,5 @@ categoryFactory = $categoryFactory; + $this->db = $db; + $params = ComponentHelper::getParams('com_weblinks'); + $this->noIDs = (bool) $params->get('sef_ids'); + $categories = new RouterViewConfiguration('categories'); + $categories->setKey('id'); + $this->registerView($categories); + $category = new RouterViewConfiguration('category'); + $category->setKey('id')->setParent($categories, 'catid')->setNestable(); + $this->registerView($category); + $webLink = new RouterViewConfiguration('weblink'); + $webLink->setKey('id')->setParent($category, 'catid'); + $this->registerView($webLink); + $form = new RouterViewConfiguration('form'); + $form->setKey('w_id'); + $this->registerView($form); + parent::__construct($app, $menu); + $this->attachRule(new MenuRules($this)); + $this->attachRule(new StandardRules($this)); + $this->attachRule(new NomenuRules($this)); + } - /** - * The category factory - * - * @var CategoryFactoryInterface - * - * @since 4.0.0 - */ - private $categoryFactory; + /** + * Method to get the segment(s) for a category + * + * @param string $id ID of the category to retrieve the segments for + * @param array $query The request that is built right now + * + * @return array|string The segments of this item + */ + public function getCategorySegment($id, $query) + { + $category = $this->getCategories()->get($id); + if ($category) { + $path = array_reverse($category->getPath(), true); + $path[0] = '1:root'; + if ($this->noIDs) { + foreach ($path as &$segment) { + list($id, $segment) = explode(':', $segment, 2); + } + } - /** - * The category cache - * - * @var array - * - * @since 4.0.0 - */ - private $categoryCache = []; + return $path; + } - /** - * The db - * - * @var DatabaseInterface - * - * @since 4.0.0 - */ - private $db; + return []; + } - /** - * Weblinks Component router constructor - * - * @param SiteApplication $app The application object - * @param AbstractMenu $menu The menu object to work with - * @param CategoryFactoryInterface $categoryFactory The category object - * @param DatabaseInterface $db The database object - */ - public function __construct(SiteApplication $app, AbstractMenu $menu, CategoryFactoryInterface $categoryFactory, DatabaseInterface $db) - { - $this->categoryFactory = $categoryFactory; - $this->db = $db; + /** + * Method to get the segment(s) for a category + * + * @param string $id ID of the category to retrieve the segments for + * @param array $query The request that is built right now + * + * @return array|string The segments of this item + */ + public function getCategoriesSegment($id, $query) + { + return $this->getCategorySegment($id, $query); + } - $params = ComponentHelper::getParams('com_weblinks'); - $this->noIDs = (bool) $params->get('sef_ids'); - $categories = new RouterViewConfiguration('categories'); - $categories->setKey('id'); - $this->registerView($categories); - $category = new RouterViewConfiguration('category'); - $category->setKey('id')->setParent($categories, 'catid')->setNestable(); - $this->registerView($category); - $webLink = new RouterViewConfiguration('weblink'); - $webLink->setKey('id')->setParent($category, 'catid'); - $this->registerView($webLink); - $form = new RouterViewConfiguration('form'); - $form->setKey('w_id'); - $this->registerView($form); + /** + * Method to get the segment(s) for a weblink + * + * @param string $id ID of the weblink to retrieve the segments for + * @param array $query The request that is built right now + * + * @return array|string The segments of this item + */ + public function getWeblinkSegment($id, $query) + { + if (!strpos($id, ':')) { + $id = (int) $id; + $dbquery = $this->db->getQuery(true); + $dbquery->select($this->db->quoteName('alias')) + ->from($this->db->quoteName('#__weblinks')) + ->where($this->db->quoteName('id') . ' = :id') + ->bind(':id', $id, ParameterType::INTEGER); + $this->db->setQuery($dbquery); + $id .= ':' . $this->db->loadResult(); + } - parent::__construct($app, $menu); + if ($this->noIDs) { + list($void, $segment) = explode(':', $id, 2); + return [$void => $segment]; + } - $this->attachRule(new MenuRules($this)); - $this->attachRule(new StandardRules($this)); - $this->attachRule(new NomenuRules($this)); - } + return [(int) $id => $id]; + } - /** - * Method to get the segment(s) for a category - * - * @param string $id ID of the category to retrieve the segments for - * @param array $query The request that is built right now - * - * @return array|string The segments of this item - */ - public function getCategorySegment($id, $query) - { - $category = $this->getCategories()->get($id); + /** + * Method to get the segment(s) for a form + * + * @param string $id ID of the weblink form to retrieve the segments for + * @param array $query The request that is built right now + * + * @return array|string The segments of this item + * + * @since 4.0.0 + */ + public function getFormSegment($id, $query) + { + return $this->getWeblinkSegment($id, $query); + } - if ($category) - { - $path = array_reverse($category->getPath(), true); - $path[0] = '1:root'; + /** + * Method to get the id for a category + * + * @param string $segment Segment to retrieve the ID for + * @param array $query The request that is parsed right now + * + * @return mixed The id of this item or false + */ + public function getCategoryId($segment, $query) + { + if (isset($query['id'])) { + $category = $this->getCategories(['access' => false])->get($query['id']); + if ($category) { + foreach ($category->getChildren() as $child) { + if ($this->noIDs) { + if ($child->alias == $segment) { + return $child->id; + } + } else { + if ($child->id == (int) $segment) { + return $child->id; + } + } + } + } + } - if ($this->noIDs) - { - foreach ($path as &$segment) - { - list($id, $segment) = explode(':', $segment, 2); - } - } + return false; + } - return $path; - } + /** + * Method to get the segment(s) for a category + * + * @param string $segment Segment to retrieve the ID for + * @param array $query The request that is parsed right now + * + * @return mixed The id of this item or false + */ + public function getCategoriesId($segment, $query) + { + return $this->getCategoryId($segment, $query); + } - return array(); - } + /** + * Method to get the segment(s) for a weblink + * + * @param string $segment Segment of the weblink to retrieve the ID for + * @param array $query The request that is parsed right now + * + * @return mixed The id of this item or false + */ + public function getWeblinkId($segment, $query) + { + if ($this->noIDs) { + $dbquery = $this->db->getQuery(true); + $dbquery->select($this->db->quoteName('id')) + ->from($this->db->quoteName('#__weblinks')) + ->where([ + $this->db->quoteName('alias') . ' = :alias', + $this->db->quoteName('catid') . ' = :catid', + ]) + ->bind(':alias', $segment) + ->bind(':catid', $query['id'], ParameterType::INTEGER); + $this->db->setQuery($dbquery); + return (int) $this->db->loadResult(); + } - /** - * Method to get the segment(s) for a category - * - * @param string $id ID of the category to retrieve the segments for - * @param array $query The request that is built right now - * - * @return array|string The segments of this item - */ - public function getCategoriesSegment($id, $query) - { - return $this->getCategorySegment($id, $query); - } + return (int) $segment; + } - /** - * Method to get the segment(s) for a weblink - * - * @param string $id ID of the weblink to retrieve the segments for - * @param array $query The request that is built right now - * - * @return array|string The segments of this item - */ - public function getWeblinkSegment($id, $query) - { - if (!strpos($id, ':')) - { - $id = (int) $id; - $dbquery = $this->db->getQuery(true); - $dbquery->select($this->db->quoteName('alias')) - ->from($this->db->quoteName('#__weblinks')) - ->where($this->db->quoteName('id') . ' = :id') - ->bind(':id', $id, ParameterType::INTEGER); - $this->db->setQuery($dbquery); + /** + * Method to get categories from cache + * + * @param array $options The options for retrieving categories + * + * @return CategoryInterface The object containing categories + * + * @since 4.0.0 + */ + private function getCategories(array $options = []): CategoryInterface + { + $key = serialize($options); + if (!isset($this->categoryCache[$key])) { + $this->categoryCache[$key] = $this->categoryFactory->createCategory($options); + } - $id .= ':' . $this->db->loadResult(); - } - - if ($this->noIDs) - { - list($void, $segment) = explode(':', $id, 2); - - return array($void => $segment); - } - - return array((int) $id => $id); - } - - /** - * Method to get the segment(s) for a form - * - * @param string $id ID of the weblink form to retrieve the segments for - * @param array $query The request that is built right now - * - * @return array|string The segments of this item - * - * @since 4.0.0 - */ - public function getFormSegment($id, $query) - { - return $this->getWeblinkSegment($id, $query); - } - - /** - * Method to get the id for a category - * - * @param string $segment Segment to retrieve the ID for - * @param array $query The request that is parsed right now - * - * @return mixed The id of this item or false - */ - public function getCategoryId($segment, $query) - { - if (isset($query['id'])) - { - $category = $this->getCategories(['access' => false])->get($query['id']); - - if ($category) - { - foreach ($category->getChildren() as $child) - { - if ($this->noIDs) - { - if ($child->alias == $segment) - { - return $child->id; - } - } - else - { - if ($child->id == (int) $segment) - { - return $child->id; - } - } - } - } - } - - return false; - } - - /** - * Method to get the segment(s) for a category - * - * @param string $segment Segment to retrieve the ID for - * @param array $query The request that is parsed right now - * - * @return mixed The id of this item or false - */ - public function getCategoriesId($segment, $query) - { - return $this->getCategoryId($segment, $query); - } - - /** - * Method to get the segment(s) for a weblink - * - * @param string $segment Segment of the weblink to retrieve the ID for - * @param array $query The request that is parsed right now - * - * @return mixed The id of this item or false - */ - public function getWeblinkId($segment, $query) - { - if ($this->noIDs) - { - $dbquery = $this->db->getQuery(true); - $dbquery->select($this->db->quoteName('id')) - ->from($this->db->quoteName('#__weblinks')) - ->where( - [ - $this->db->quoteName('alias') . ' = :alias', - $this->db->quoteName('catid') . ' = :catid', - ] - ) - ->bind(':alias', $segment) - ->bind(':catid', $query['id'], ParameterType::INTEGER); - $this->db->setQuery($dbquery); - - return (int) $this->db->loadResult(); - } - - return (int) $segment; - } - - /** - * Method to get categories from cache - * - * @param array $options The options for retrieving categories - * - * @return CategoryInterface The object containing categories - * - * @since 4.0.0 - */ - private function getCategories(array $options = []): CategoryInterface - { - $key = serialize($options); - - if (!isset($this->categoryCache[$key])) - { - $this->categoryCache[$key] = $this->categoryFactory->createCategory($options); - } - - return $this->categoryCache[$key]; - } + return $this->categoryCache[$key]; + } } diff --git a/src/components/com_weblinks/src/View/Categories/HtmlView.php b/src/components/com_weblinks/src/View/Categories/HtmlView.php index 8e30794..0e1e0dc 100644 --- a/src/components/com_weblinks/src/View/Categories/HtmlView.php +++ b/src/components/com_weblinks/src/View/Categories/HtmlView.php @@ -1,4 +1,5 @@ items as $item) { + $item->slug = $item->alias ? ($item->id . ':' . $item->alias) : $item->id; + $temp = $item->params; + $item->params = clone $this->params; + $item->params->merge($temp); + if ($item->params->get('count_clicks', 1) == 1) { + $item->link = Route::_('index.php?option=com_weblinks&task=weblink.go&id=' . $item->id); + } else { + $item->link = $item->url; + } + } - /** - * Execute and display a template script. - * - * @param string $tpl The name of the template file to parse; automatically searches through the template paths. - * - * @return mixed A string if successful, otherwise a Error object. - */ - public function display($tpl = null) - { - parent::commonCategoryDisplay(); + return parent::display($tpl); + } - // Prepare the data. - // Compute the weblink slug & link url. - foreach ($this->items as $item) - { - $item->slug = $item->alias ? ($item->id . ':' . $item->alias) : $item->id; - $temp = $item->params; - $item->params = clone $this->params; - $item->params->merge($temp); + /** + * Prepares the document + * + * @return void + */ + protected function prepareDocument() + { + parent::prepareDocument(); + parent::addFeed(); + if ($this->menuItemMatchCategory) { + // If the active menu item is linked directly to the category being displayed, no further process is needed + return; + } - if ($item->params->get('count_clicks', 1) == 1) - { - $item->link = Route::_('index.php?option=com_weblinks&task=weblink.go&id=' . $item->id); - } - else - { - $item->link = $item->url; - } - } + // Get ID of the category from active menu item + $menu = $this->menu; - return parent::display($tpl); - } + if ( + $menu && $menu->component == 'com_weblinks' && isset($menu->query['view']) + && in_array($menu->query['view'], ['categories', 'category']) + ) { + $id = $menu->query['id']; + } else { + $id = 0; + } - /** - * Prepares the document - * - * @return void - */ - protected function prepareDocument() - { - parent::prepareDocument(); + $path = [['title' => $this->category->title, 'link' => '']]; + $category = $this->category->getParent(); + while ($category !== null && $category->id != $id && $category->id !== 'root') { + $path[] = ['title' => $category->title, 'link' => RouteHelper::getCategoryRoute($category->id, $category->language)]; + $category = $category->getParent(); + } - parent::addFeed(); - - if ($this->menuItemMatchCategory) - { - // If the active menu item is linked directly to the category being displayed, no further process is needed - return; - } - - // Get ID of the category from active menu item - $menu = $this->menu; - - if ($menu && $menu->component == 'com_weblinks' && isset($menu->query['view']) - && in_array($menu->query['view'], ['categories', 'category'])) - { - $id = $menu->query['id']; - } - else - { - $id = 0; - } - - $path = [['title' => $this->category->title, 'link' => '']]; - $category = $this->category->getParent(); - - while ($category !== null && $category->id != $id && $category->id !== 'root') - { - $path[] = ['title' => $category->title, 'link' => RouteHelper::getCategoryRoute($category->id, $category->language)]; - $category = $category->getParent(); - } - - $path = array_reverse($path); - - foreach ($path as $item) - { - $this->pathway->addItem($item['title'], $item['link']); - } - } + $path = array_reverse($path); + foreach ($path as $item) { + $this->pathway->addItem($item['title'], $item['link']); + } + } } diff --git a/src/components/com_weblinks/src/View/Form/HtmlView.php b/src/components/com_weblinks/src/View/Form/HtmlView.php index 00348d1..dfa26f7 100644 --- a/src/components/com_weblinks/src/View/Form/HtmlView.php +++ b/src/components/com_weblinks/src/View/Form/HtmlView.php @@ -1,4 +1,5 @@ getCurrentUser(); + /** + * Display the view. + * + * @param string $tpl The name of the template file to parse; automatically searches through the template paths. + * + * @return mixed A string if successful, otherwise an Error object. + */ + public function display($tpl = null) + { + $user = $this->getCurrentUser(); - // Get model data. - $this->state = $this->get('State'); - $this->item = $this->get('Item'); - $this->form = $this->get('Form'); - $this->return_page = $this->get('ReturnPage'); + // Get model data. + $this->state = $this->get('State'); + $this->item = $this->get('Item'); + $this->form = $this->get('Form'); + $this->return_page = $this->get('ReturnPage'); - if (empty($this->item->id)) - { - $authorised = $user->authorise('core.create', 'com_weblinks') || count($user->getAuthorisedCategories('com_weblinks', 'core.create')); - } - else - { - $authorised = $user->authorise('core.edit', 'com_weblinks.category.' . $this->item->catid); - } + if (empty($this->item->id)) { + $authorised = $user->authorise('core.create', 'com_weblinks') || count($user->getAuthorisedCategories('com_weblinks', 'core.create')); + } else { + $authorised = $user->authorise('core.edit', 'com_weblinks.category.' . $this->item->catid); + } - if ($authorised !== true) - { - throw new \Exception(Text::_('JERROR_ALERTNOAUTHOR'), 403); - } + if ($authorised !== true) { + throw new \Exception(Text::_('JERROR_ALERTNOAUTHOR'), 403); + } - if (!empty($this->item)) - { - // Override the base weblink data with any data in the session. - $temp = (array) Factory::getApplication()->getUserState('com_weblinks.edit.weblink.data', array()); + if (!empty($this->item)) { + // Override the base weblink data with any data in the session. + $temp = (array) Factory::getApplication()->getUserState('com_weblinks.edit.weblink.data', []); - foreach ($temp as $k => $v) - { - $this->item->$k = $v; - } + foreach ($temp as $k => $v) { + $this->item->$k = $v; + } - $this->form->bind($this->item); - } + $this->form->bind($this->item); + } - // Check for errors. - if (count($errors = $this->get('Errors'))) - { - throw new GenericDataException(implode("\n", $errors), 500); - } + // Check for errors. + if (count($errors = $this->get('Errors'))) { + throw new GenericDataException(implode("\n", $errors), 500); + } - // Create a shortcut to the parameters. - $params = &$this->state->params; + // Create a shortcut to the parameters. + $params = &$this->state->params; - // Escape strings for HTML output - $this->pageclass_sfx = htmlspecialchars($params->get('pageclass_sfx', '')); + // Escape strings for HTML output + $this->pageclass_sfx = htmlspecialchars($params->get('pageclass_sfx', '')); - $this->params = $params; - $this->user = $user; + $this->params = $params; + $this->user = $user; - $this->_prepareDocument(); + $this->prepareDocument(); - parent::display($tpl); - } + parent::display($tpl); + } - /** - * Prepares the document - * - * @return void - */ - protected function _prepareDocument() - { - $app = Factory::getApplication(); + /** + * Prepares the document + * + * @return void + */ + protected function prepareDocument() + { + $app = Factory::getApplication(); - // Because the application sets a default page title, - // we need to get it from the menu item itself - $menu = $app->getMenu()->getActive(); + // Because the application sets a default page title, + // we need to get it from the menu item itself + $menu = $app->getMenu()->getActive(); - if (empty($this->item->id)) - { - $head = Text::_('COM_WEBLINKS_FORM_SUBMIT_WEBLINK'); - } - else - { - $head = Text::_('COM_WEBLINKS_FORM_EDIT_WEBLINK'); - } + if (empty($this->item->id)) { + $head = Text::_('COM_WEBLINKS_FORM_SUBMIT_WEBLINK'); + } else { + $head = Text::_('COM_WEBLINKS_FORM_EDIT_WEBLINK'); + } - if ($menu) - { - $this->params->def('page_heading', $this->params->get('page_title', $menu->title)); - } - else - { - $this->params->def('page_heading', $head); - } + if ($menu) { + $this->params->def('page_heading', $this->params->get('page_title', $menu->title)); + } else { + $this->params->def('page_heading', $head); + } - $title = $this->params->def('page_title', $head); + $title = $this->params->def('page_title', $head); - $this->setDocumentTitle($title); + $this->setDocumentTitle($title); - if ($this->params->get('menu-meta_description')) - { - $this->document->setDescription($this->params->get('menu-meta_description')); - } + if ($this->params->get('menu-meta_description')) { + $this->document->setDescription($this->params->get('menu-meta_description')); + } - if ($this->params->get('menu-meta_keywords')) - { - $this->document->setMetadata('keywords', $this->params->get('menu-meta_keywords')); - } + if ($this->params->get('menu-meta_keywords')) { + $this->document->setMetadata('keywords', $this->params->get('menu-meta_keywords')); + } - if ($this->params->get('robots')) - { - $this->document->setMetadata('robots', $this->params->get('robots')); - } - } + if ($this->params->get('robots')) { + $this->document->setMetadata('robots', $this->params->get('robots')); + } + } } diff --git a/src/components/com_weblinks/src/View/Weblink/HtmlView.php b/src/components/com_weblinks/src/View/Weblink/HtmlView.php index 3a05ff3..c69e295 100644 --- a/src/components/com_weblinks/src/View/Weblink/HtmlView.php +++ b/src/components/com_weblinks/src/View/Weblink/HtmlView.php @@ -1,4 +1,5 @@ item = $this->get('Item'); - $this->state = $this->get('State'); - $this->params = $this->state->get('params'); - - // Create a shortcut for $item. - $item = $this->item; - - $item->slug = $item->alias ? ($item->id . ':' . $item->alias) : $item->id; - - $temp = $item->params; - $item->params = clone $app->getParams(); - $item->params->merge($temp); - - $offset = $this->state->get('list.offset'); - - $app->triggerEvent('onContentPrepare', array('com_weblinks.weblink', &$item, &$item->params, $offset)); - - $item->event = new \stdClass; - - $results = $app->triggerEvent('onContentAfterTitle', array('com_weblinks.weblink', &$item, &$item->params, $offset)); - $item->event->afterDisplayTitle = trim(implode("\n", $results)); - - $results = $app->triggerEvent('onContentBeforeDisplay', array('com_weblinks.weblink', &$item, &$item->params, $offset)); - $item->event->beforeDisplayContent = trim(implode("\n", $results)); - - $results = $app->triggerEvent('onContentAfterDisplay', array('com_weblinks.weblink', &$item, &$item->params, $offset)); - $item->event->afterDisplayContent = trim(implode("\n", $results)); - - parent::display($tpl); - } + /** + * The weblink object + * + * @var \JObject + */ + protected $item; + /** + * The page parameters + * + * @var \Joomla\Registry\Registry|null + */ + protected $params; + /** + * The item model state + * + * @var \Joomla\Registry\Registry + * @since 1.6 + */ + protected $state; + /** + * Execute and display a template script. + * + * @param string $tpl The name of the template file to parse; automatically searches through the template paths. + * + * @return mixed A string if successful, otherwise an Error object. + * + * @since __DEPLOY_VERSION__ + */ + public function display($tpl = null) + { + $app = Factory::getApplication(); + $this->item = $this->get('Item'); + $this->state = $this->get('State'); + $this->params = $this->state->get('params'); + // Create a shortcut for $item. + $item = $this->item; + $item->slug = $item->alias ? ($item->id . ':' . $item->alias) : $item->id; + $temp = $item->params; + $item->params = clone $app->getParams(); + $item->params->merge($temp); + $offset = $this->state->get('list.offset'); + $app->triggerEvent('onContentPrepare', ['com_weblinks.weblink', &$item, &$item->params, $offset]); + $item->event = new \stdClass(); + $results = $app->triggerEvent('onContentAfterTitle', ['com_weblinks.weblink', &$item, &$item->params, $offset]); + $item->event->afterDisplayTitle = trim(implode("\n", $results)); + $results = $app->triggerEvent('onContentBeforeDisplay', ['com_weblinks.weblink', &$item, &$item->params, $offset]); + $item->event->beforeDisplayContent = trim(implode("\n", $results)); + $results = $app->triggerEvent('onContentAfterDisplay', ['com_weblinks.weblink', &$item, &$item->params, $offset]); + $item->event->afterDisplayContent = trim(implode("\n", $results)); + parent::display($tpl); + } } diff --git a/src/components/com_weblinks/tmpl/categories/default.php b/src/components/com_weblinks/tmpl/categories/default.php index c7b77a1..2dc2f62 100644 --- a/src/components/com_weblinks/tmpl/categories/default.php +++ b/src/components/com_weblinks/tmpl/categories/default.php @@ -1,4 +1,5 @@ document->getWebAssetManager(); $wa->getRegistry()->addExtensionRegistryFile('com_categories'); @@ -23,8 +23,8 @@ $wa->usePreset('com_categories.shared-categories-accordion'); ?> diff --git a/src/components/com_weblinks/tmpl/categories/default_items.php b/src/components/com_weblinks/tmpl/categories/default_items.php index 200094d..22d52e9 100644 --- a/src/components/com_weblinks/tmpl/categories/default_items.php +++ b/src/components/com_weblinks/tmpl/categories/default_items.php @@ -1,4 +1,5 @@ maxLevelcat != 0 && count($this->items[$this->parent->id]) > 0) : -?> -
- items[$this->parent->id] as $id => $item) : ?> - params->get('show_empty_categories_cat') || $item->numitems || count($item->getChildren())) : ?> -
-
- - escape($item->title); ?> - params->get('show_cat_num_links_cat') == 1) :?> - -   - numitems; ?> - - - maxLevelcat > 1 && count($item->getChildren()) > 0) : ?> - - -
+ ?> +
+ items[$this->parent->id] as $id => $item) : + ?> + params->get('show_empty_categories_cat') || $item->numitems || count($item->getChildren())) : + ?> +
+
+ + escape($item->title); ?> + params->get('show_cat_num_links_cat') == 1) : + ?> + +   + numitems; ?> + + + maxLevelcat > 1 && count($item->getChildren()) > 0) : + ?> + + +
- params->get('show_subcat_desc_cat') == 1 && !empty($item->description)) : ?> -
- description, '', 'com_weblinks.categories'); ?> -
- + params->get('show_subcat_desc_cat') == 1 && !empty($item->description)) : + ?> +
+ description, '', 'com_weblinks.categories'); ?> +
+ - params->get('show_description_image') && !empty($item->getParams()->get('image'))) : ?> - getParams(); - $img = HTMLHelper::cleanImageURL($params->get('image')); - $alt = ''; - if (!empty($params->get('image_alt'))) : - $alt = 'alt="' . htmlspecialchars($params->get('image_alt'), ENT_COMPAT, 'UTF-8') . '"'; - elseif (!empty($params->get('image_alt_empty'))) : - $alt = 'alt=""'; - endif; - ?> - > - + params->get('show_description_image') && !empty($item->getParams()->get('image'))) : + ?> + getParams(); + $img = HTMLHelper::cleanImageURL($params->get('image')); + $alt = ''; + if (!empty($params->get('image_alt'))) : + $alt = 'alt="' . htmlspecialchars($params->get('image_alt'), ENT_COMPAT, 'UTF-8') . '"'; + elseif (!empty($params->get('image_alt_empty'))) : + $alt = 'alt=""'; + endif; + ?> + > + - maxLevelcat > 1 && count($item->getChildren()) > 0) : ?> - - -
- - -
- + maxLevelcat > 1 && count($item->getChildren()) > 0) : + ?> + + +
+ + +
+ diff --git a/src/components/com_weblinks/tmpl/category/default.php b/src/components/com_weblinks/tmpl/category/default.php index a5990da..3cc3746 100644 --- a/src/components/com_weblinks/tmpl/category/default.php +++ b/src/components/com_weblinks/tmpl/category/default.php @@ -1,4 +1,5 @@ \ No newline at end of file + subtemplatename = 'items'; + echo LayoutHelper::render('joomla.content.category_default', $this); + ?> + diff --git a/src/components/com_weblinks/tmpl/category/default_children.php b/src/components/com_weblinks/tmpl/category/default_children.php index b128610..cfde6a1 100644 --- a/src/components/com_weblinks/tmpl/category/default_children.php +++ b/src/components/com_weblinks/tmpl/category/default_children.php @@ -1,4 +1,5 @@ maxLevel != 0 && count($this->children[$this->category->id]) > 0) : -?> - - + getChildren()) > 0) : + $this->children[$child->id] = $child->getChildren(); + $this->category = $child; + $this->maxLevel--; + echo $this->loadTemplate('children'); + $this->category = $child->getParent(); + $this->maxLevel++; + endif; ?> + + + + + diff --git a/src/components/com_weblinks/tmpl/category/default_items.php b/src/components/com_weblinks/tmpl/category/default_items.php index 685dbba..38458d8 100644 --- a/src/components/com_weblinks/tmpl/category/default_items.php +++ b/src/components/com_weblinks/tmpl/category/default_items.php @@ -1,4 +1,5 @@ getIdentity(); - // Check if user is allowed to add/edit based on weblinks permission. $canEdit = $user->authorise('core.edit', 'com_weblinks.category.' . $this->category->id); $canEditOwn = $user->authorise('core.edit.own', 'com_weblinks.category.' . $this->category->id); $canCreate = $user->authorise('core.create', 'com_weblinks.category.' . $this->category->id); - $listOrder = $this->escape($this->state->get('list.ordering')); $listDirn = $this->escape($this->state->get('list.direction')); ?> + - params->get('show_pagination')) : ?> - - pagination->getPagesLinks(); ?> - - + + + - + params->get('show_pagination')) : + ?> + + + + + + + category, $this->category->params); ?> + + diff --git a/src/components/com_weblinks/tmpl/form/edit.php b/src/components/com_weblinks/tmpl/form/edit.php index 5170723..02fbb63 100644 --- a/src/components/com_weblinks/tmpl/form/edit.php +++ b/src/components/com_weblinks/tmpl/form/edit.php @@ -1,4 +1,5 @@ params->get('captcha', Factory::getApplication()->get('captcha', '0')); - -foreach (PluginHelper::getPlugin('captcha') as $plugin) -{ - if ($captchaSet === $plugin->name) - { - $captchaEnabled = true; - break; - } +foreach (PluginHelper::getPlugin('captcha') as $plugin) { + if ($captchaSet === $plugin->name) { + $captchaEnabled = true; + break; + } } // Create shortcut to parameters. $params = $this->state->get('params'); ?>
- params->get('show_page_heading')) : ?> - - -
+ params->get('show_page_heading')) : + ?> + + + - form->renderField('title'); ?> - form->renderField('alias'); ?> - form->renderField('catid'); ?> - form->renderField('url'); ?> - form->renderField('tags'); ?> + form->renderField('title'); ?> + form->renderField('alias'); ?> + form->renderField('catid'); ?> + form->renderField('url'); ?> + form->renderField('tags'); ?> - get('save_history', 0)) : ?> - form->renderField('version_note'); ?> - + get('save_history', 0)) : + ?> + form->renderField('version_note'); ?> + - user->authorise('core.edit.state', 'com_weblinks.weblink')) : ?> - form->renderField('state'); ?> - - form->renderField('language'); ?> - form->renderField('description'); ?> + user->authorise('core.edit.state', 'com_weblinks.weblink')) : + ?> + form->renderField('state'); ?> + + form->renderField('language'); ?> + form->renderField('description'); ?> - form->renderField('image_first', 'images'); ?> - form->renderField('image_first_alt', 'images'); ?> - form->renderField('image_first_alt_empty', 'images'); ?> - form->renderField('float_first', 'images'); ?> - form->renderField('image_first_caption', 'images'); ?> + form->renderField('image_first', 'images'); ?> + form->renderField('image_first_alt', 'images'); ?> + form->renderField('image_first_alt_empty', 'images'); ?> + form->renderField('float_first', 'images'); ?> + form->renderField('image_first_caption', 'images'); ?> - form->renderField('image_second', 'images'); ?> - form->renderField('image_second_alt', 'images'); ?> - form->renderField('image_second_alt_empty', 'images'); ?> - form->renderField('float_second', 'images'); ?> - form->renderField('image_second_caption', 'images'); ?> + form->renderField('image_second', 'images'); ?> + form->renderField('image_second_alt', 'images'); ?> + form->renderField('image_second_alt_empty', 'images'); ?> + form->renderField('float_second', 'images'); ?> + form->renderField('image_second_caption', 'images'); ?> - -
- form->renderField('captcha'); ?> -
- + +
+ form->renderField('captcha'); ?> +
+ -
- - - params->get('save_history', 0) && $this->item->id) : ?> - form->getInput('contenthistory'); ?> - -
+
+ + + params->get('save_history', 0) && $this->item->id) : + ?> + form->getInput('contenthistory'); ?> + +
- - - -
+ + + +
diff --git a/src/components/com_weblinks/tmpl/weblink/default.php b/src/components/com_weblinks/tmpl/weblink/default.php index ca40dc6..46eb7b9 100644 --- a/src/components/com_weblinks/tmpl/weblink/default.php +++ b/src/components/com_weblinks/tmpl/weblink/default.php @@ -1,4 +1,5 @@ item->url); $user = Factory::getApplication()->getIdentity(); - $canEdit = $user->authorise('core.edit', 'com_weblinks.category.' . $this->item->catid); - -if (!$canEdit) -{ - $canEditOwn = $user->authorise('core.edit.own', 'com_weblinks.category.' . $this->item->catid); - $canEdit = $canEditOwn && $this->item->created_by == $user->id; +if (!$canEdit) { + $canEditOwn = $user->authorise('core.edit.own', 'com_weblinks.category.' . $this->item->catid); + $canEdit = $canEditOwn && $this->item->created_by == $user->id; } ?>
- - - -
-
-
- item, $this->item->params); ?> -
-
-
- + + + +
+
+
+ item, $this->item->params); ?> +
+
+
+ - - item->event->afterDisplayTitle; ?> + + item->event->afterDisplayTitle; ?> - - item->event->beforeDisplayContent; ?> + + item->event->beforeDisplayContent; ?> -
-
- -
+
+
+ +
- params->get('show_tags', 1) && !empty($this->item->tags->itemTags)) : ?> -
- item->tags->itemTags); ?> -
- + params->get('show_tags', 1) && !empty($this->item->tags->itemTags)) : + ?> +
+ item->tags->itemTags); ?> +
+ -
- item->images); ?> - image_first)) : ?> - - float_first)) : ?> - float_first == 'right' ? 'float-end' : 'float-start'; ?> - - image_first); ?> - image_first_alt) && empty($images->image_first_alt_empty) - ? '' - : 'alt="' . htmlspecialchars($images->image_first_alt, ENT_COMPAT, 'UTF-8') . '"'; ?> -
- itemprop="thumbnail" /> - image_first_caption)) : ?> -
image_first_caption, ENT_COMPAT, 'UTF-8'); ?>
- -
- +
+ item->images); ?> + image_first)) : + ?> + + float_first)) : + ?> + float_first == 'right' ? 'float-end' : 'float-start'; ?> + + image_first); ?> + image_first_alt) && empty($images->image_first_alt_empty) + ? '' + : 'alt="' . htmlspecialchars($images->image_first_alt, ENT_COMPAT, 'UTF-8') . '"'; ?> +
+ itemprop="thumbnail" /> + image_first_caption)) : + ?> +
image_first_caption, ENT_COMPAT, 'UTF-8'); ?>
+ +
+ - image_second)) : ?> - - float_second)) : ?> - float_second == 'right' ? 'float-end' : 'float-start'; ?> - - image_second); ?> - image_second_alt) && empty($images->image_second_alt_empty) - ? '' - : 'alt="' . htmlspecialchars($images->image_second_alt, ENT_COMPAT, 'UTF-8') . '"'; ?> -
- itemprop="thumbnail" /> - image_second_caption)) : ?> -
image_second_caption, ENT_COMPAT, 'UTF-8'); ?>
- -
- + image_second)) : + ?> + + float_second)) : + ?> + float_second == 'right' ? 'float-end' : 'float-start'; ?> + + image_second); ?> + image_second_alt) && empty($images->image_second_alt_empty) + ? '' + : 'alt="' . htmlspecialchars($images->image_second_alt, ENT_COMPAT, 'UTF-8') . '"'; ?> +
+ itemprop="thumbnail" /> + image_second_caption)) : + ?> +
image_second_caption, ENT_COMPAT, 'UTF-8'); ?>
+ +
+ - item->description)) : ?> - item->description; ?> - + item->description)) : + ?> + item->description; ?> + -
+
-
- - item->event->afterDisplayContent; ?> +
+ + item->event->afterDisplayContent; ?>
diff --git a/src/modules/mod_weblinks/mod_weblinks.xml b/src/modules/mod_weblinks/mod_weblinks.xml index 9e5077b..64432e9 100644 --- a/src/modules/mod_weblinks/mod_weblinks.xml +++ b/src/modules/mod_weblinks/mod_weblinks.xml @@ -1,6 +1,7 @@ mod_weblinks + mod_weblinks Joomla! Project ##DATE## Copyright (C) 2005 - 2017 Open Source Matters. All rights reserved. diff --git a/src/modules/mod_weblinks/services/provider.php b/src/modules/mod_weblinks/services/provider.php index 75815ef..e663c2f 100644 --- a/src/modules/mod_weblinks/services/provider.php +++ b/src/modules/mod_weblinks/services/provider.php @@ -8,7 +8,9 @@ * @license GNU General Public License version 2 or later; see LICENSE.txt */ -defined('_JEXEC') or die; +// phpcs:disable PSR1.Files.SideEffects +\defined('_JEXEC') or die; +// phpcs:enable PSR1.Files.SideEffects use Joomla\CMS\Extension\Service\Provider\HelperFactory; use Joomla\CMS\Extension\Service\Provider\Module; @@ -22,20 +24,20 @@ use Joomla\DI\ServiceProviderInterface; * @since __DEPLOY_VERSION__ */ return new class () implements ServiceProviderInterface { - /** - * Registers the service provider with a DI container. - * - * @param Container $container The DI container. - * - * @return void - * - * @since __DEPLOY_VERSION__ - */ - public function register(Container $container) - { - $container->registerServiceProvider(new ModuleDispatcherFactory('\\Joomla\\Module\\Weblinks')); - $container->registerServiceProvider(new HelperFactory('\\Joomla\\Module\\Weblinks\\Site\\Helper')); + /** + * Registers the service provider with a DI container. + * + * @param Container $container The DI container. + * + * @return void + * + * @since __DEPLOY_VERSION__ + */ + public function register(Container $container) + { + $container->registerServiceProvider(new ModuleDispatcherFactory('\\Joomla\\Module\\Weblinks')); + $container->registerServiceProvider(new HelperFactory('\\Joomla\\Module\\Weblinks\\Site\\Helper')); - $container->registerServiceProvider(new Module()); - } + $container->registerServiceProvider(new Module()); + } }; diff --git a/src/modules/mod_weblinks/src/Dispatcher/Dispatcher.php b/src/modules/mod_weblinks/src/Dispatcher/Dispatcher.php index 9df4bd2..55a1ec6 100644 --- a/src/modules/mod_weblinks/src/Dispatcher/Dispatcher.php +++ b/src/modules/mod_weblinks/src/Dispatcher/Dispatcher.php @@ -14,9 +14,11 @@ use Joomla\CMS\Dispatcher\AbstractModuleDispatcher; use Joomla\CMS\Helper\HelperFactoryAwareInterface; use Joomla\CMS\Helper\HelperFactoryAwareTrait; +// phpcs:disable PSR1.Files.SideEffects // phpcs:disable PSR1.Files.SideEffects \defined('_JEXEC') or die; // phpcs:enable PSR1.Files.SideEffects +// phpcs:enable PSR1.Files.SideEffects /** * Dispatcher class for mod_weblinks @@ -25,26 +27,26 @@ use Joomla\CMS\Helper\HelperFactoryAwareTrait; */ class Dispatcher extends AbstractModuleDispatcher implements HelperFactoryAwareInterface { - use HelperFactoryAwareTrait; + use HelperFactoryAwareTrait; - /** - * Returns the layout data. - * - * @return array - * - * @since __DEPLOY_VERSION__ - */ - protected function getLayoutData() - { - $data = parent::getLayoutData(); + /** + * Returns the layout data. + * + * @return array + * + * @since __DEPLOY_VERSION__ + */ + protected function getLayoutData() + { + $data = parent::getLayoutData(); - $data['list'] = $this->getHelperFactory()->getHelper('WeblinksHelper')->getWeblinks( - $data['params'], - $this->getApplication() - ); + $data['list'] = $this->getHelperFactory()->getHelper('WeblinksHelper')->getWeblinks( + $data['params'], + $this->getApplication() + ); - $data['moduleclass_sfx'] = htmlspecialchars($data['params']->get('moduleclass_sfx', '')); + $data['moduleclass_sfx'] = htmlspecialchars($data['params']->get('moduleclass_sfx', '')); - return $data; - } + return $data; + } } diff --git a/src/modules/mod_weblinks/src/Helper/WeblinksHelper.php b/src/modules/mod_weblinks/src/Helper/WeblinksHelper.php index c476ea9..9a1c773 100644 --- a/src/modules/mod_weblinks/src/Helper/WeblinksHelper.php +++ b/src/modules/mod_weblinks/src/Helper/WeblinksHelper.php @@ -1,4 +1,5 @@ bootComponent('com_weblinks')->getMVCFactory() - ->createModel('Category', 'Site', ['ignore_request' => true]); + /** + * Retrieve list of weblinks + * + * @param Registry $params The module parameters + * @param CMSApplicationInterface $app The application + * + * @return array Array containing all the weblinks. + * + * @since __DEPLOY_VERSION__ + **/ + public function getWeblinks($params, $app) + { + // @var \Joomla\Component\Weblinks\Site\Model\CategoryModel $model + $model = $app->bootComponent('com_weblinks')->getMVCFactory() + ->createModel('Category', 'Site', ['ignore_request' => true]); - // Set application parameters in model - $cParams = ComponentHelper::getParams('com_weblinks'); - $model->setState('params', $cParams); + // Set application parameters in model + $cParams = ComponentHelper::getParams('com_weblinks'); + $model->setState('params', $cParams); - // Set the filters based on the module params - $model->setState('list.start', 0); - $model->setState('list.limit', (int) $params->get('count', 5)); + // Set the filters based on the module params + $model->setState('list.start', 0); + $model->setState('list.limit', (int) $params->get('count', 5)); - $model->setState('filter.state', 1); - $model->setState('filter.publish_date', true); + $model->setState('filter.state', 1); + $model->setState('filter.publish_date', true); - // Access filter - $access = !ComponentHelper::getParams('com_weblinks')->get('show_noauth'); - $model->setState('filter.access', $access); + // Access filter + $access = !ComponentHelper::getParams('com_weblinks')->get('show_noauth'); + $model->setState('filter.access', $access); - $ordering = $params->get('ordering', 'ordering'); - $model->setState('list.ordering', $ordering == 'order' ? 'ordering' : $ordering); - $model->setState('list.direction', $params->get('direction', 'asc')); + $ordering = $params->get('ordering', 'ordering'); + $model->setState('list.ordering', $ordering == 'order' ? 'ordering' : $ordering); + $model->setState('list.direction', $params->get('direction', 'asc')); - $catid = (int) $params->get('catid', 0); - $model->setState('category.id', $catid); - $model->setState('category.group', $params->get('groupby', 0)); - $model->setState('category.ordering', $params->get('groupby_ordering', 'c.lft')); - $model->setState('category.direction', $params->get('groupby_direction', 'ASC')); + $catid = (int) $params->get('catid', 0); + $model->setState('category.id', $catid); + $model->setState('category.group', $params->get('groupby', 0)); + $model->setState('category.ordering', $params->get('groupby_ordering', 'c.lft')); + $model->setState('category.direction', $params->get('groupby_direction', 'ASC')); - // Create query object - $db = $model->getDbo(); - $query = $db->getQuery(true); + // Create query object + $db = $model->getDbo(); + $query = $db->getQuery(true); - $case_when1 = ' CASE WHEN '; - $case_when1 .= $query->charLength('a.alias', '!=', '0'); - $case_when1 .= ' THEN '; - $a_id = $query->castAs('CHAR', 'a.id'); - $case_when1 .= $query->concatenate([$a_id, 'a.alias'], ':'); - $case_when1 .= ' ELSE '; - $case_when1 .= $a_id . ' END as slug'; + $case_when1 = ' CASE WHEN '; + $case_when1 .= $query->charLength('a.alias', '!=', '0'); + $case_when1 .= ' THEN '; + $a_id = $query->castAs('CHAR', 'a.id'); + $case_when1 .= $query->concatenate([$a_id, 'a.alias'], ':'); + $case_when1 .= ' ELSE '; + $case_when1 .= $a_id . ' END as slug'; - $case_when2 = ' CASE WHEN '; - $case_when2 .= $query->charLength('c.alias', '!=', '0'); - $case_when2 .= ' THEN '; - $c_id = $query->castAs('CHAR', 'c.id'); - $case_when2 .= $query->concatenate([$c_id, 'c.alias'], ':'); - $case_when2 .= ' ELSE '; - $case_when2 .= $c_id . ' END as catslug'; + $case_when2 = ' CASE WHEN '; + $case_when2 .= $query->charLength('c.alias', '!=', '0'); + $case_when2 .= ' THEN '; + $c_id = $query->castAs('CHAR', 'c.id'); + $case_when2 .= $query->concatenate([$c_id, 'c.alias'], ':'); + $case_when2 .= ' ELSE '; + $case_when2 .= $c_id . ' END as catslug'; - $model->setState( - 'list.select', - 'a.*, c.description AS c_description, c.published AS c_published,' . $case_when1 . ',' . $case_when2 - ); + $model->setState( + 'list.select', + 'a.*, c.description AS c_description, c.published AS c_published,' . $case_when1 . ',' . $case_when2 + ); - $model->setState('filter.c.published', 1); + $model->setState('filter.c.published', 1); - // Filter by language - $model->setState('filter.language', $app->getLanguageFilter()); + // Filter by language + $model->setState('filter.language', $app->getLanguageFilter()); - $items = $model->getItems(); + $items = $model->getItems(); - if ($items) - { - foreach ($items as $item) - { - $temp = $item->params; - $item->params = clone $cParams; - $item->params->merge($temp); + if ($items) { + foreach ($items as $item) { + $temp = $item->params; + $item->params = clone $cParams; + $item->params->merge($temp); - if ($item->params->get('count_clicks', 1) == 1) - { - $item->link = Route::_('index.php?option=com_weblinks&task=weblink.go&catid=' . $item->catslug . '&id=' . $item->slug); - } - else - { - $item->link = $item->url; - } - } + if ($item->params->get('count_clicks', 1) == 1) { + $item->link = Route::_('index.php?option=com_weblinks&task=weblink.go&catid=' . $item->catslug . '&id=' . $item->slug); + } else { + $item->link = $item->url; + } + } - return $items; - } + return $items; + } - return []; - } + return []; + } - /** - * Retrieve list of weblinks - * - * @param Registry $params The module parameters - * @param CMSApplicationInterface $app The application - * - * @return mixed Null if no weblinks based on input parameters else an array containing all the weblinks. - * - * @since 1.5 - * - * @deprecated 5.0 Use the none static function getWeblinks - **/ - public static function getList($params, $app) - { - return (new self())->getWeblinks($params, $app); - } + /** + * Retrieve list of weblinks + * + * @param Registry $params The module parameters + * @param CMSApplicationInterface $app The application + * + * @return mixed Null if no weblinks based on input parameters else an array containing all the weblinks. + * + * @since 1.5 + * + * @deprecated 5.0 Use the none static function getWeblinks + **/ + public static function getList($params, $app) + { + return (new self())->getWeblinks($params, $app); + } } diff --git a/src/modules/mod_weblinks/tmpl/default.php b/src/modules/mod_weblinks/tmpl/default.php index 0cac7fb..e24b891 100644 --- a/src/modules/mod_weblinks/tmpl/default.php +++ b/src/modules/mod_weblinks/tmpl/default.php @@ -1,4 +1,5 @@ -get('groupby', 0)) : ?> - - get('groupby_columns', 3); ?> - - $l->catid, 'title' => $l->category_title); ?> - - - $cat) : ?> - - - catid == $cat['catid']) : ?> - - - - 1) :?> - -
- -
- - get('groupby_showtitle', 1)) :?> - - ; -
    - -
  • -
    - link; - $width = (int) $item->params->get('width', 600); - $height = (int) $item->params->get('height', 500); +get('groupby', 0)) : + ?> + + get('groupby_columns', 3); ?> + + $l->catid, 'title' => $l->category_title); ?> + + + $cat) : + ?> + + + catid == $cat['catid']) : + ?> + + + + 1) : + ?> + +
    + +
    + + get('groupby_showtitle', 1)) : + ?> + + ; +
      + +
    • +
      + link; + $width = (int) $item->params->get('width', 600); + $height = (int) $item->params->get('height', 500); + switch ($item->params->get('target')) { + case 1: + // Open in a new window + echo '' . + htmlspecialchars($item->title, ENT_COMPAT, 'UTF-8') . ''; + break; + case 2: + // Open in a popup window + $attribs = 'toolbar=no,location=no,status=no,menubar=no,scrollbars=yes,resizable=yes,width=' . $width . ',height=' . $height; + echo "" . + htmlspecialchars($item->title, ENT_COMPAT, 'UTF-8') . ''; - switch ($item->params->get('target')) - { - case 1: - // Open in a new window - echo '' . - htmlspecialchars($item->title, ENT_COMPAT, 'UTF-8') . ''; - break; - case 2: - // Open in a popup window - $attribs = 'toolbar=no,location=no,status=no,menubar=no,scrollbars=yes,resizable=yes,width=' . $width . ',height=' . $height; - echo "" . - htmlspecialchars($item->title, ENT_COMPAT, 'UTF-8') . ''; - break; - case 3: - // Open in a modal window - $modalId = 'weblink-item-modal-' . $item->id; - $modalParams['title'] = htmlspecialchars($item->title, ENT_COMPAT, 'UTF-8'); - $modalParams['url'] = $link; - $modalParams['height'] = '100%'; - $modalParams['width'] = '100%'; - $modalParams['bodyHeight'] = 70; - $modalParams['modalWidth'] = 80; - echo HTMLHelper::_('bootstrap.renderModal', $modalId, $modalParams); - echo ''; - break; - default: - // Open in parent window - echo '' . - htmlspecialchars($item->title, ENT_COMPAT, 'UTF-8') . ''; - break; - } - ?> -
      - get('description', 0) ? '
      ' . $item->description . '
      ' : ''; ?> - get('hits', 0)) : ?> -
      - hits . ' ' . Text::_('MOD_WEBLINKS_HITS'); ?> -
      - -
    • - -
    - 1) :?> -
    - -
    - - - - -
      - -
    • -
      - link; - $width = (int) $item->params->get('width', 600); - $height = (int) $item->params->get('height', 500); + break; + case 3: + // Open in a modal window + $modalId = 'weblink-item-modal-' . $item->id; + $modalParams['title'] = htmlspecialchars($item->title, ENT_COMPAT, 'UTF-8'); + $modalParams['url'] = $link; + $modalParams['height'] = '100%'; + $modalParams['width'] = '100%'; + $modalParams['bodyHeight'] = 70; + $modalParams['modalWidth'] = 80; + echo HTMLHelper::_('bootstrap.renderModal', $modalId, $modalParams); + echo ''; - switch ($item->params->get('target')) - { - case 1: - // Open in a new window - echo '' . - htmlspecialchars($item->title, ENT_COMPAT, 'UTF-8') . ''; - break; - case 2: - // Open in a popup window - $attribs = 'toolbar=no,location=no,status=no,menubar=no,scrollbars=yes,resizable=yes,width=' . $width . ',height=' . $height; - echo "" . - htmlspecialchars($item->title, ENT_COMPAT, 'UTF-8') . ''; - break; - case 3: - // Open in a modal window - $modalId = 'weblink-item-modal-' . $item->id; - $modalParams['title'] = htmlspecialchars($item->title, ENT_COMPAT, 'UTF-8'); - $modalParams['url'] = $link; - $modalParams['height'] = '100%'; - $modalParams['width'] = '100%'; - $modalParams['bodyHeight'] = 70; - $modalParams['modalWidth'] = 80; - echo HTMLHelper::_('bootstrap.renderModal', $modalId, $modalParams); - echo '
      + get('description', 0) ? '
      ' . $item->description . '
      ' : ''; ?> + get('hits', 0)) : + ?> +
      + hits . ' ' . Text::_('MOD_WEBLINKS_HITS'); ?> +
      + +
    • + +
    + 1) : + ?> +
    + +
    + + + + +
      + +
    • +
      + link; + $width = (int) $item->params->get('width', 600); + $height = (int) $item->params->get('height', 500); + switch ($item->params->get('target')) { + case 1: + // Open in a new window + echo '' . + htmlspecialchars($item->title, ENT_COMPAT, 'UTF-8') . ''; + + break; + case 2: + // Open in a popup window + $attribs = 'toolbar=no,location=no,status=no,menubar=no,scrollbars=yes,resizable=yes,width=' . $width . ',height=' . $height; + echo "" . + htmlspecialchars($item->title, ENT_COMPAT, 'UTF-8') . ''; + + break; + case 3: + // Open in a modal window + $modalId = 'weblink-item-modal-' . $item->id; + $modalParams['title'] = htmlspecialchars($item->title, ENT_COMPAT, 'UTF-8'); + $modalParams['url'] = $link; + $modalParams['height'] = '100%'; + $modalParams['width'] = '100%'; + $modalParams['bodyHeight'] = 70; + $modalParams['modalWidth'] = 80; + echo HTMLHelper::_('bootstrap.renderModal', $modalId, $modalParams); + echo ''; - break; - default: - // Open in parent window - echo '' . - htmlspecialchars($item->title, ENT_COMPAT, 'UTF-8') . ''; - break; - } - ?> -
      - get('description', 0) ? '
      ' . $item->description . '
      ' : ''; ?> - get('hits', 0)) : ?> -
      - hits . ' ' . Text::_('MOD_WEBLINKS_HITS'); ?> -
      - -
    • - -
    - + + break; + default: + // Open in parent window + echo '' . + htmlspecialchars($item->title, ENT_COMPAT, 'UTF-8') . ''; + + break; + } + ?> +
+ get('description', 0) ? '
' . $item->description . '
' : ''; ?> + get('hits', 0)) : + ?> +
+ hits . ' ' . Text::_('MOD_WEBLINKS_HITS'); ?> +
+ + + + + diff --git a/src/plugins/editors-xtd/weblink/services/provider.php b/src/plugins/editors-xtd/weblink/services/provider.php index 418d626..6789c09 100644 --- a/src/plugins/editors-xtd/weblink/services/provider.php +++ b/src/plugins/editors-xtd/weblink/services/provider.php @@ -8,7 +8,9 @@ * @license GNU General Public License version 2 or later; see LICENSE.txt */ -defined('_JEXEC') or die; +// phpcs:disable PSR1.Files.SideEffects +\defined('_JEXEC') or die; +// phpcs:enable PSR1.Files.SideEffects use Joomla\CMS\Extension\PluginInterface; use Joomla\CMS\Factory; @@ -19,29 +21,29 @@ use Joomla\Event\DispatcherInterface; use Joomla\Plugin\EditorsXtd\Weblink\Extension\Weblink; return new class () implements ServiceProviderInterface { - /** - * Registers the service provider with a DI container. - * - * @param Container $container The DI container. - * - * @return void - * - * @since __DEPLOY_VERSION__ - */ - public function register(Container $container) - { - $container->set( - PluginInterface::class, - function (Container $container) { - $app = Factory::getApplication(); - $dispatcher = $container->get(DispatcherInterface::class); + /** + * Registers the service provider with a DI container. + * + * @param Container $container The DI container. + * + * @return void + * + * @since __DEPLOY_VERSION__ + */ + public function register(Container $container) + { + $container->set( + PluginInterface::class, + function (Container $container) { + $app = Factory::getApplication(); + $dispatcher = $container->get(DispatcherInterface::class); - return new Weblink( - $dispatcher, - (array) PluginHelper::getPlugin('editors-xtd', 'weblink'), - $app - ); - } - ); - } + return new Weblink( + $dispatcher, + (array) PluginHelper::getPlugin('editors-xtd', 'weblink'), + $app + ); + } + ); + } }; diff --git a/src/plugins/editors-xtd/weblink/src/Extension/Weblink.php b/src/plugins/editors-xtd/weblink/src/Extension/Weblink.php index de0ce28..3b19457 100644 --- a/src/plugins/editors-xtd/weblink/src/Extension/Weblink.php +++ b/src/plugins/editors-xtd/weblink/src/Extension/Weblink.php @@ -1,4 +1,5 @@ setApplication($application); - } + $this->setApplication($application); + } - /** - * Display the button - * - * @param string $name The name of the button to add - * - * @return CMSObject The button options as JObject - * - * @since __DEPLOY_VERSION__ - */ - public function onDisplay($name) - { - $user = $this->getApplication()->getIdentity(); + /** + * Display the button + * + * @param string $name The name of the button to add + * + * @return CMSObject The button options as JObject + * + * @since __DEPLOY_VERSION__ + */ + public function onDisplay($name) + { + $user = $this->getApplication()->getIdentity(); - if ($user->authorise('core.create', 'com_weblinks') - || $user->authorise('core.edit', 'com_weblinks') - || $user->authorise('core.edit.own', 'com_weblinks')) - { - // The URL for the weblinks list - $link = 'index.php?option=com_weblinks&view=weblinks&layout=modal&tmpl=component&' - . Session::getFormToken() . '=1&editor=' . $name; + if ( + $user->authorise('core.create', 'com_weblinks') + || $user->authorise('core.edit', 'com_weblinks') + || $user->authorise('core.edit.own', 'com_weblinks') + ) { + // The URL for the weblinks list + $link = 'index.php?option=com_weblinks&view=weblinks&layout=modal&tmpl=component&' + . Session::getFormToken() . '=1&editor=' . $name; - $button = new CMSObject; - $button->modal = true; - $button->link = $link; - $button->text = Text::_('PLG_EDITORS-XTD_WEBLINK_BUTTON_WEBLINK'); - $button->name = $this->_type . '_' . $this->_name; - $button->icon = 'globe'; - $button->iconSVG = ' + $button = new CMSObject(); + $button->modal = true; + $button->link = $link; + $button->text = Text::_('PLG_EDITORS-XTD_WEBLINK_BUTTON_WEBLINK'); + $button->name = $this->_type . '_' . $this->_name; + $button->icon = 'globe'; + // phpcs:disable Generic.Files.LineLength + $button->iconSVG = ' '; + // phpcs:enable Generic.Files.LineLength + $button->options = [ + 'height' => '300px', + 'width' => '800px', + 'bodyHeight' => '70', + 'modalWidth' => '80', + ]; - $button->options = [ - 'height' => '300px', - 'width' => '800px', - 'bodyHeight' => '70', - 'modalWidth' => '80', - ]; - - return $button; - } - } + return $button; + } + } } diff --git a/src/plugins/finder/weblinks/services/provider.php b/src/plugins/finder/weblinks/services/provider.php index 5147ef3..1e724df 100644 --- a/src/plugins/finder/weblinks/services/provider.php +++ b/src/plugins/finder/weblinks/services/provider.php @@ -8,7 +8,9 @@ * @license GNU General Public License version 2 or later; see LICENSE.txt */ -defined('_JEXEC') or die; +// phpcs:disable PSR1.Files.SideEffects +\defined('_JEXEC') or die; +// phpcs:enable PSR1.Files.SideEffects use Joomla\CMS\Extension\PluginInterface; use Joomla\CMS\Plugin\PluginHelper; @@ -19,29 +21,29 @@ use Joomla\Event\DispatcherInterface; use Joomla\Plugin\Finder\Weblinks\Extension\Weblinks; return new class () implements ServiceProviderInterface { - /** - * Registers the service provider with a DI container. - * - * @param Container $container The DI container. - * - * @return void - * - * @since __DEPLOY_VERSION__ - */ - public function register(Container $container) - { - $container->set( - PluginInterface::class, - function (Container $container) { - $dispatcher = $container->get(DispatcherInterface::class); - $database = $container->get(DatabaseInterface::class); + /** + * Registers the service provider with a DI container. + * + * @param Container $container The DI container. + * + * @return void + * + * @since __DEPLOY_VERSION__ + */ + public function register(Container $container) + { + $container->set( + PluginInterface::class, + function (Container $container) { + $dispatcher = $container->get(DispatcherInterface::class); + $database = $container->get(DatabaseInterface::class); - return new Weblinks( - $dispatcher, - (array) PluginHelper::getPlugin('finder', 'weblinks'), - $database - ); - } - ); - } + return new Weblinks( + $dispatcher, + (array) PluginHelper::getPlugin('finder', 'weblinks'), + $database + ); + } + ); + } }; diff --git a/src/plugins/finder/weblinks/src/Extension/Weblinks.php b/src/plugins/finder/weblinks/src/Extension/Weblinks.php index 1144c53..0341ce8 100644 --- a/src/plugins/finder/weblinks/src/Extension/Weblinks.php +++ b/src/plugins/finder/weblinks/src/Extension/Weblinks.php @@ -1,4 +1,5 @@ setDatabase($database); - } + $this->setDatabase($database); + } - /** - * Method to update the item link information when the item category is - * changed. This is fired when the item category is published or unpublished - * from the list view. - * - * @param string $extension The extension whose category has been updated. - * @param array $pks An array of primary key ids of the content that has changed state. - * @param integer $value The value of the state that the content has been changed to. - * - * @return void - * - * @since 2.5 - */ - public function onFinderCategoryChangeState($extension, $pks, $value) - { - // Make sure we're handling com_weblinks categories. - if ($extension == 'com_weblinks') - { - $this->categoryStateChange($pks, $value); - } - } + /** + * Method to update the item link information when the item category is + * changed. This is fired when the item category is published or unpublished + * from the list view. + * + * @param string $extension The extension whose category has been updated. + * @param array $pks An array of primary key ids of the content that has changed state. + * @param integer $value The value of the state that the content has been changed to. + * + * @return void + * + * @since 2.5 + */ + public function onFinderCategoryChangeState($extension, $pks, $value) + { + // Make sure we're handling com_weblinks categories. + if ($extension == 'com_weblinks') { + $this->categoryStateChange($pks, $value); + } + } - /** - * Method to remove the link information for items that have been deleted. - * - * @param string $context The context of the action being performed. - * @param Table $table A JTable object containing the record to be deleted. - * - * @return boolean True on success. - * - * @throws \Exception on database error. - * @since 2.5 - */ - public function onFinderAfterDelete($context, $table) - { - if ($context == 'com_weblinks.weblink') - { - $id = $table->id; - } - elseif ($context == 'com_finder.index') - { - $id = $table->link_id; - } - else - { - return true; - } + /** + * Method to remove the link information for items that have been deleted. + * + * @param string $context The context of the action being performed. + * @param Table $table A JTable object containing the record to be deleted. + * + * @return boolean True on success. + * + * @throws \Exception on database error. + * @since 2.5 + */ + public function onFinderAfterDelete($context, $table) + { + if ($context == 'com_weblinks.weblink') { + $id = $table->id; + } elseif ($context == 'com_finder.index') { + $id = $table->link_id; + } else { + return true; + } - // Remove the item from the index. - return $this->remove($id); - } + // Remove the item from the index. + return $this->remove($id); + } - /** - * Smart Search after content save method. - * Reindexes the link information for a weblink that has been saved. - * It also makes adjustments if the access level of a weblink item or - * the category to which it belongs has been changed. - * - * @param string $context The context of the content passed to the plugin. - * @param Table $row A JTable object. - * @param boolean $isNew True if the content has just been created. - * - * @return boolean True on success. - * - * @throws \Exception on database error. - * @since 2.5 - */ - public function onFinderAfterSave($context, $row, $isNew) - { - // We only want to handle web links here. We need to handle front end and back end editing. - if ($context == 'com_weblinks.weblink' || $context == 'com_weblinks.form') - { - // Check if the access levels are different. - if (!$isNew && $this->old_access != $row->access) - { - // Process the change. - $this->itemAccessChange($row); - } + /** + * Smart Search after content save method. + * Reindexes the link information for a weblink that has been saved. + * It also makes adjustments if the access level of a weblink item or + * the category to which it belongs has been changed. + * + * @param string $context The context of the content passed to the plugin. + * @param Table $row A JTable object. + * @param boolean $isNew True if the content has just been created. + * + * @return boolean True on success. + * + * @throws \Exception on database error. + * @since 2.5 + */ + public function onFinderAfterSave($context, $row, $isNew) + { + // We only want to handle web links here. We need to handle front end and back end editing. + if ($context == 'com_weblinks.weblink' || $context == 'com_weblinks.form') { + // Check if the access levels are different. + if (!$isNew && $this->old_access != $row->access) { + // Process the change. + $this->itemAccessChange($row); + } - // Reindex the item. - $this->reindex($row->id); - } + // Reindex the item. + $this->reindex($row->id); + } - // Check for access changes in the category. - if ($context == 'com_categories.category') - { - // Check if the access levels are different. - if (!$isNew && $this->old_cataccess != $row->access) - { - $this->categoryAccessChange($row); - } - } + // Check for access changes in the category. + if ($context == 'com_categories.category') { + // Check if the access levels are different. + if (!$isNew && $this->old_cataccess != $row->access) { + $this->categoryAccessChange($row); + } + } - return true; - } + return true; + } - /** - * Smart Search before content save method. - * This event is fired before the data is actually saved. - * - * @param string $context The context of the content passed to the plugin. - * @param Table $row A JTable object. - * @param boolean $isNew True if the content is just about to be created. - * - * @return boolean True on success. - * - * @throws \Exception on database error. - * @since 2.5 - */ - public function onFinderBeforeSave($context, $row, $isNew) - { - // We only want to handle web links here. - if ($context == 'com_weblinks.weblink' || $context == 'com_weblinks.form') - { - // Query the database for the old access level if the item isn't new. - if (!$isNew) - { - $this->checkItemAccess($row); - } - } + /** + * Smart Search before content save method. + * This event is fired before the data is actually saved. + * + * @param string $context The context of the content passed to the plugin. + * @param Table $row A JTable object. + * @param boolean $isNew True if the content is just about to be created. + * + * @return boolean True on success. + * + * @throws \Exception on database error. + * @since 2.5 + */ + public function onFinderBeforeSave($context, $row, $isNew) + { + // We only want to handle web links here. + if ($context == 'com_weblinks.weblink' || $context == 'com_weblinks.form') { + // Query the database for the old access level if the item isn't new. + if (!$isNew) { + $this->checkItemAccess($row); + } + } - // Check for access levels from the category. - if ($context == 'com_categories.category') - { - // Query the database for the old access level if the item isn't new. - if (!$isNew) - { - $this->checkCategoryAccess($row); - } - } + // Check for access levels from the category. + if ($context == 'com_categories.category') { + // Query the database for the old access level if the item isn't new. + if (!$isNew) { + $this->checkCategoryAccess($row); + } + } - return true; - } + return true; + } - /** - * Method to update the link information for items that have been changed - * from outside the edit screen. This is fired when the item is published, - * unpublished, archived, or unarchived from the list view. - * - * @param string $context The context for the content passed to the plugin. - * @param array $pks An array of primary key ids of the content that has changed state. - * @param integer $value The value of the state that the content has been changed to. - * - * @return void - * - * @since 2.5 - */ - public function onFinderChangeState($context, $pks, $value) - { - // We only want to handle web links here. - if ($context == 'com_weblinks.weblink' || $context == 'com_weblinks.form') - { - $this->itemStateChange($pks, $value); - } + /** + * Method to update the link information for items that have been changed + * from outside the edit screen. This is fired when the item is published, + * unpublished, archived, or unarchived from the list view. + * + * @param string $context The context for the content passed to the plugin. + * @param array $pks An array of primary key ids of the content that has changed state. + * @param integer $value The value of the state that the content has been changed to. + * + * @return void + * + * @since 2.5 + */ + public function onFinderChangeState($context, $pks, $value) + { + // We only want to handle web links here. + if ($context == 'com_weblinks.weblink' || $context == 'com_weblinks.form') { + $this->itemStateChange($pks, $value); + } - // Handle when the plugin is disabled. - if ($context == 'com_plugins.plugin' && $value === 0) - { - $this->pluginDisable($pks); - } - } + // Handle when the plugin is disabled. + if ($context == 'com_plugins.plugin' && $value === 0) { + $this->pluginDisable($pks); + } + } - /** - * Method to index an item. The item must be a FinderIndexerResult object. - * - * @param Result $item The item to index as an FinderIndexerResult object. - * - * @return void - * - * @throws \Exception on database error. - * @since 2.5 - */ - protected function index(Result $item) - { - // Check if the extension is enabled - if (ComponentHelper::isEnabled($this->extension) == false) - { - return; - } + /** + * Method to index an item. The item must be a FinderIndexerResult object. + * + * @param Result $item The item to index as an FinderIndexerResult object. + * + * @return void + * + * @throws \Exception on database error. + * @since 2.5 + */ + protected function index(Result $item) + { + // Check if the extension is enabled + if (ComponentHelper::isEnabled($this->extension) == false) { + return; + } - $item->setLanguage(); + $item->setLanguage(); - // Initialise the item parameters. - $item->params = new Registry($item->params); - $item->metadata = new Registry($item->metadata); + // Initialise the item parameters. + $item->params = new Registry($item->params); + $item->metadata = new Registry($item->metadata); - // Build the necessary route and path information. - $item->url = $this->getURL($item->id, $this->extension, $this->layout); - $item->route = RouteHelper::getWeblinkRoute($item->slug, $item->catslug, $item->language); + // Build the necessary route and path information. + $item->url = $this->getURL($item->id, $this->extension, $this->layout); + $item->route = RouteHelper::getWeblinkRoute($item->slug, $item->catslug, $item->language); - /* - * Add the meta-data processing instructions based on the newsfeeds - * configuration parameters. - */ - // Add the meta-author. - $item->metaauthor = $item->metadata->get('author'); + /* + * Add the meta-data processing instructions based on the newsfeeds + * configuration parameters. + */ + // Add the meta-author. + $item->metaauthor = $item->metadata->get('author'); - // Handle the link to the meta-data. - $item->addInstruction(Indexer::META_CONTEXT, 'link'); - $item->addInstruction(Indexer::META_CONTEXT, 'metakey'); - $item->addInstruction(Indexer::META_CONTEXT, 'metadesc'); - $item->addInstruction(Indexer::META_CONTEXT, 'metaauthor'); - $item->addInstruction(Indexer::META_CONTEXT, 'author'); - $item->addInstruction(Indexer::META_CONTEXT, 'created_by_alias'); + // Handle the link to the meta-data. + $item->addInstruction(Indexer::META_CONTEXT, 'link'); + $item->addInstruction(Indexer::META_CONTEXT, 'metakey'); + $item->addInstruction(Indexer::META_CONTEXT, 'metadesc'); + $item->addInstruction(Indexer::META_CONTEXT, 'metaauthor'); + $item->addInstruction(Indexer::META_CONTEXT, 'author'); + $item->addInstruction(Indexer::META_CONTEXT, 'created_by_alias'); - // Translate the state. Weblinks should only be published if the category is published and also ensure that 'state' for trashed items is set to zero - $item->state = $this->translateState($item->state, $item->cat_state); + // Translate the state. Weblinks should only be published if the category is published and also ensure that 'state' for trashed items is set to zero + $item->state = $this->translateState($item->state, $item->cat_state); - // Add the type taxonomy data. - $item->addTaxonomy('Type', 'Web Link'); + // Add the type taxonomy data. + $item->addTaxonomy('Type', 'Web Link'); - // Add the category taxonomy data. - $categories = Categories::getInstance('com_weblinks', ['published' => false, 'access' => false]); - $category = $categories->get($item->catid); + // Add the category taxonomy data. + $categories = Categories::getInstance('com_weblinks', ['published' => false, 'access' => false]); + $category = $categories->get($item->catid); - // Category does not exist, stop here - if (!$category) - { - return; - } + // Category does not exist, stop here + if (!$category) { + return; + } - $item->addNestedTaxonomy('Category', $category, $this->translateState($category->published), $category->access, $category->language); + $item->addNestedTaxonomy('Category', $category, $this->translateState($category->published), $category->access, $category->language); - // Add the language taxonomy data. - $item->addTaxonomy('Language', $item->language); + // Add the language taxonomy data. + $item->addTaxonomy('Language', $item->language); - // Get content extras. - Helper::getContentExtras($item); + // Get content extras. + Helper::getContentExtras($item); - // Index the item. - $this->indexer->index($item); - } + // Index the item. + $this->indexer->index($item); + } - /** - * Method to setup the indexer to be run. - * - * @return boolean True on success. - * - * @since 2.5 - */ - protected function setup() - { - return true; - } + /** + * Method to setup the indexer to be run. + * + * @return boolean True on success. + * + * @since 2.5 + */ + protected function setup() + { + return true; + } - /** - * Method to get the SQL query used to retrieve the list of content items. - * - * @param mixed $query A JDatabaseQuery object or null. - * - * @return DatabaseQuery A database object. - * - * @since 2.5 - */ - protected function getListQuery($query = null) - { - $db = $this->getDatabase(); + /** + * Method to get the SQL query used to retrieve the list of content items. + * + * @param mixed $query A JDatabaseQuery object or null. + * + * @return DatabaseQuery A database object. + * + * @since 2.5 + */ + protected function getListQuery($query = null) + { + $db = $this->getDatabase(); - // Check if we can use the supplied SQL query. - $query = $query instanceof DatabaseQuery ? $query : $db->getQuery(true) - ->select('a.id, a.catid, a.title, a.alias, a.url AS link, a.description AS summary') - ->select('a.metakey, a.metadesc, a.metadata, a.language, a.access, a.ordering') - ->select('a.created_by_alias, a.modified, a.modified_by') - ->select('a.publish_up AS publish_start_date, a.publish_down AS publish_end_date') - ->select('a.state AS state, a.created AS start_date, a.params') - ->select('c.title AS category, c.published AS cat_state, c.access AS cat_access'); + // Check if we can use the supplied SQL query. + $query = $query instanceof DatabaseQuery ? $query : $db->getQuery(true) + ->select('a.id, a.catid, a.title, a.alias, a.url AS link, a.description AS summary') + ->select('a.metakey, a.metadesc, a.metadata, a.language, a.access, a.ordering') + ->select('a.created_by_alias, a.modified, a.modified_by') + ->select('a.publish_up AS publish_start_date, a.publish_down AS publish_end_date') + ->select('a.state AS state, a.created AS start_date, a.params') + ->select('c.title AS category, c.published AS cat_state, c.access AS cat_access'); - // Handle the alias CASE WHEN portion of the query. - $case_when_item_alias = ' CASE WHEN '; - $case_when_item_alias .= $query->charLength('a.alias', '!=', '0'); - $case_when_item_alias .= ' THEN '; - $a_id = $query->castAs('CHAR', 'a.id'); - $case_when_item_alias .= $query->concatenate([$a_id, 'a.alias'], ':'); - $case_when_item_alias .= ' ELSE '; - $case_when_item_alias .= $a_id . ' END as slug'; - $query->select($case_when_item_alias); + // Handle the alias CASE WHEN portion of the query. + $case_when_item_alias = ' CASE WHEN '; + $case_when_item_alias .= $query->charLength('a.alias', '!=', '0'); + $case_when_item_alias .= ' THEN '; + $a_id = $query->castAs('CHAR', 'a.id'); + $case_when_item_alias .= $query->concatenate([$a_id, 'a.alias'], ':'); + $case_when_item_alias .= ' ELSE '; + $case_when_item_alias .= $a_id . ' END as slug'; + $query->select($case_when_item_alias); - $case_when_category_alias = ' CASE WHEN '; - $case_when_category_alias .= $query->charLength('c.alias', '!=', '0'); - $case_when_category_alias .= ' THEN '; - $c_id = $query->castAs('CHAR', 'c.id'); - $case_when_category_alias .= $query->concatenate([$c_id, 'c.alias'], ':'); - $case_when_category_alias .= ' ELSE '; - $case_when_category_alias .= $c_id . ' END as catslug'; - $query->select($case_when_category_alias) - ->from('#__weblinks AS a') - ->join('LEFT', '#__categories AS c ON c.id = a.catid'); + $case_when_category_alias = ' CASE WHEN '; + $case_when_category_alias .= $query->charLength('c.alias', '!=', '0'); + $case_when_category_alias .= ' THEN '; + $c_id = $query->castAs('CHAR', 'c.id'); + $case_when_category_alias .= $query->concatenate([$c_id, 'c.alias'], ':'); + $case_when_category_alias .= ' ELSE '; + $case_when_category_alias .= $c_id . ' END as catslug'; + $query->select($case_when_category_alias) + ->from('#__weblinks AS a') + ->join('LEFT', '#__categories AS c ON c.id = a.catid'); - return $query; - } + return $query; + } - /** - * Method to get the query clause for getting items to update by time. - * - * @param string $time The modified timestamp. - * - * @return DatabaseQuery A database object. - * - * @since 2.5 - */ - protected function getUpdateQueryByTime($time) - { - // Build an SQL query based on the modified time. - $db = $this->getDatabase(); - $query = $db->getQuery(true) - ->where('a.date >= ' . $db->quote($time)); + /** + * Method to get the query clause for getting items to update by time. + * + * @param string $time The modified timestamp. + * + * @return DatabaseQuery A database object. + * + * @since 2.5 + */ + protected function getUpdateQueryByTime($time) + { + // Build an SQL query based on the modified time. + $db = $this->getDatabase(); + $query = $db->getQuery(true) + ->where('a.date >= ' . $db->quote($time)); - return $query; - } + return $query; + } } diff --git a/src/plugins/search/weblinks/services/provider.php b/src/plugins/search/weblinks/services/provider.php index 47f24db..1a7c075 100644 --- a/src/plugins/search/weblinks/services/provider.php +++ b/src/plugins/search/weblinks/services/provider.php @@ -8,7 +8,9 @@ * @license GNU General Public License version 2 or later; see LICENSE.txt */ -defined('_JEXEC') or die; +// phpcs:disable PSR1.Files.SideEffects +\defined('_JEXEC') or die; +// phpcs:enable PSR1.Files.SideEffects use Joomla\CMS\Extension\PluginInterface; use Joomla\CMS\Factory; @@ -20,31 +22,31 @@ use Joomla\Event\DispatcherInterface; use Joomla\Plugin\Search\Weblinks\Extension\Weblinks; return new class () implements ServiceProviderInterface { - /** - * Registers the service provider with a DI container. - * - * @param Container $container The DI container. - * - * @return void - * - * @since __DEPLOY_VERSION__ - */ - public function register(Container $container) - { - $container->set( - PluginInterface::class, - function (Container $container) { - $app = Factory::getApplication(); - $dispatcher = $container->get(DispatcherInterface::class); - $database = $container->get(DatabaseInterface::class); + /** + * Registers the service provider with a DI container. + * + * @param Container $container The DI container. + * + * @return void + * + * @since __DEPLOY_VERSION__ + */ + public function register(Container $container) + { + $container->set( + PluginInterface::class, + function (Container $container) { + $app = Factory::getApplication(); + $dispatcher = $container->get(DispatcherInterface::class); + $database = $container->get(DatabaseInterface::class); - return new Weblinks( - $dispatcher, - (array) PluginHelper::getPlugin('finder', 'weblinks'), - $app, - $database - ); - } - ); - } + return new Weblinks( + $dispatcher, + (array) PluginHelper::getPlugin('finder', 'weblinks'), + $app, + $database + ); + } + ); + } }; diff --git a/src/plugins/search/weblinks/src/Extension/Weblinks.php b/src/plugins/search/weblinks/src/Extension/Weblinks.php index 5864c4d..a7a2812 100644 --- a/src/plugins/search/weblinks/src/Extension/Weblinks.php +++ b/src/plugins/search/weblinks/src/Extension/Weblinks.php @@ -1,4 +1,5 @@ setApplication($application); - $this->setDatabase($database); - } + $this->setApplication($application); + $this->setDatabase($database); + } - /** - * Determine areas searchable by this plugin. - * - * @return array An array of search areas. - * - * @since 1.6 - */ - public function onContentSearchAreas() - { - static $areas = [ - 'weblinks' => 'PLG_SEARCH_WEBLINKS_WEBLINKS', - ]; + /** + * Determine areas searchable by this plugin. + * + * @return array An array of search areas. + * + * @since 1.6 + */ + public function onContentSearchAreas() + { + static $areas = [ + 'weblinks' => 'PLG_SEARCH_WEBLINKS_WEBLINKS', + ]; - return $areas; - } + return $areas; + } - /** - * Search content (weblinks). - * - * The SQL must return the following fields that are used in a common display - * routine: href, title, section, created, text, browsernav - * - * @param string $text Target search string. - * @param string $phrase Matching option (possible values: exact|any|all). Default is "any". - * @param string $ordering Ordering option (possible values: newest|oldest|popular|alpha|category). Default is "newest". - * @param mixed $areas An array if the search it to be restricted to areas or null to search all areas. - * - * @return array Search results. - * - * @since 1.6 - */ - public function onContentSearch($text, $phrase = '', $ordering = '', $areas = null) - { - $app = $this->getApplication(); - $db = $this->getDatabase(); - $groups = $app->getIdentity()->getAuthorisedViewLevels(); + /** + * Search content (weblinks). + * + * The SQL must return the following fields that are used in a common display + * routine: href, title, section, created, text, browsernav + * + * @param string $text Target search string. + * @param string $phrase Matching option (possible values: exact|any|all). Default is "any". + * @param string $ordering Ordering option (possible values: newest|oldest|popular|alpha|category). Default is "newest". + * @param mixed $areas An array if the search it to be restricted to areas or null to search all areas. + * + * @return array Search results. + * + * @since 1.6 + */ + public function onContentSearch($text, $phrase = '', $ordering = '', $areas = null) + { + $app = $this->getApplication(); + $db = $this->getDatabase(); + $groups = $app->getIdentity()->getAuthorisedViewLevels(); - $searchText = $text; + $searchText = $text; - if (is_array($areas) - && !array_intersect($areas, array_keys($this->onContentSearchAreas()))) - { - return []; - } + if ( + is_array($areas) + && !array_intersect($areas, array_keys($this->onContentSearchAreas())) + ) { + return []; + } - $sContent = $this->params->get('search_content', 1); - $sArchived = $this->params->get('search_archived', 1); - $limit = $this->params->def('search_limit', 50); - $state = []; + $sContent = $this->params->get('search_content', 1); + $sArchived = $this->params->get('search_archived', 1); + $limit = $this->params->def('search_limit', 50); + $state = []; - if ($sContent) - { - $state[] = 1; - } + if ($sContent) { + $state[] = 1; + } - if ($sArchived) - { - $state[] = 2; - } + if ($sArchived) { + $state[] = 2; + } - if (empty($state)) - { - return []; - } + if (empty($state)) { + return []; + } - $text = trim($text); + $text = trim($text); - if ($text == '') - { - return []; - } + if ($text == '') { + return []; + } - $searchWeblinks = Text::_('PLG_SEARCH_WEBLINKS'); + $searchWeblinks = Text::_('PLG_SEARCH_WEBLINKS'); - switch ($phrase) - { - case 'exact': - $text = $db->quote('%' . $db->escape($text, true) . '%', false); - $wheres2 = []; - $wheres2[] = 'a.url LIKE ' . $text; - $wheres2[] = 'a.description LIKE ' . $text; - $wheres2[] = 'a.title LIKE ' . $text; - $where = '(' . implode(') OR (', $wheres2) . ')'; - break; + switch ($phrase) { + case 'exact': + $text = $db->quote('%' . $db->escape($text, true) . '%', false); + $wheres2 = []; + $wheres2[] = 'a.url LIKE ' . $text; + $wheres2[] = 'a.description LIKE ' . $text; + $wheres2[] = 'a.title LIKE ' . $text; + $where = '(' . implode(') OR (', $wheres2) . ')'; + break; - case 'all': - case 'any': - default: - $words = explode(' ', $text); - $wheres = []; + case 'all': + case 'any': + default: + $words = explode(' ', $text); + $wheres = []; - foreach ($words as $word) - { - $word = $db->quote('%' . $db->escape($word, true) . '%', false); - $wheres2 = []; - $wheres2[] = 'a.url LIKE ' . $word; - $wheres2[] = 'a.description LIKE ' . $word; - $wheres2[] = 'a.title LIKE ' . $word; - $wheres[] = implode(' OR ', $wheres2); - } + foreach ($words as $word) { + $word = $db->quote('%' . $db->escape($word, true) . '%', false); + $wheres2 = []; + $wheres2[] = 'a.url LIKE ' . $word; + $wheres2[] = 'a.description LIKE ' . $word; + $wheres2[] = 'a.title LIKE ' . $word; + $wheres[] = implode(' OR ', $wheres2); + } - $where = '(' . implode(($phrase == 'all' ? ') AND (' : ') OR ('), $wheres) . ')'; - break; - } + $where = '(' . implode(($phrase == 'all' ? ') AND (' : ') OR ('), $wheres) . ')'; + break; + } - switch ($ordering) - { - case 'oldest': - $order = 'a.created ASC'; - break; + switch ($ordering) { + case 'oldest': + $order = 'a.created ASC'; + break; - case 'popular': - $order = 'a.hits DESC'; - break; + case 'popular': + $order = 'a.hits DESC'; + break; - case 'alpha': - $order = 'a.title ASC'; - break; + case 'alpha': + $order = 'a.title ASC'; + break; - case 'category': - $order = 'c.title ASC, a.title ASC'; - break; + case 'category': + $order = 'c.title ASC, a.title ASC'; + break; - case 'newest': - default: - $order = 'a.created DESC'; - } + case 'newest': + default: + $order = 'a.created DESC'; + } - $query = $db->getQuery(true); + $query = $db->getQuery(true); - // SQLSRV changes. - $caseWhen = ' CASE WHEN '; - $caseWhen .= $query->charLength('a.alias', '!=', '0'); - $caseWhen .= ' THEN '; - $a_id = $query->castAs('CHAR', 'a.id'); - $caseWhen .= $query->concatenate([$a_id, 'a.alias'], ':'); - $caseWhen .= ' ELSE '; - $caseWhen .= $a_id . ' END as slug'; + // SQLSRV changes. + $caseWhen = ' CASE WHEN '; + $caseWhen .= $query->charLength('a.alias', '!=', '0'); + $caseWhen .= ' THEN '; + $a_id = $query->castAs('CHAR', 'a.id'); + $caseWhen .= $query->concatenate([$a_id, 'a.alias'], ':'); + $caseWhen .= ' ELSE '; + $caseWhen .= $a_id . ' END as slug'; - $caseWhen1 = ' CASE WHEN '; - $caseWhen1 .= $query->charLength('c.alias', '!=', '0'); - $caseWhen1 .= ' THEN '; - $c_id = $query->castAs('CHAR', 'c.id'); - $caseWhen1 .= $query->concatenate([$c_id, 'c.alias'], ':'); - $caseWhen1 .= ' ELSE '; - $caseWhen1 .= $c_id . ' END as catslug'; + $caseWhen1 = ' CASE WHEN '; + $caseWhen1 .= $query->charLength('c.alias', '!=', '0'); + $caseWhen1 .= ' THEN '; + $c_id = $query->castAs('CHAR', 'c.id'); + $caseWhen1 .= $query->concatenate([$c_id, 'c.alias'], ':'); + $caseWhen1 .= ' ELSE '; + $caseWhen1 .= $c_id . ' END as catslug'; - $query->select('a.title AS title, a.created AS created, a.url, a.description AS text, ' . $caseWhen . "," . $caseWhen1) - ->select($query->concatenate([$db->quote($searchWeblinks), 'c.title'], " / ") . ' AS section') - ->select('\'1\' AS browsernav') - ->from('#__weblinks AS a') - ->join('INNER', '#__categories as c ON c.id = a.catid') - ->where('(' . $where . ')') - ->whereIn($db->quoteName('a.state'), $state) - ->where($db->quoteName('c.published') . ' = 1') - ->whereIn($db->quoteName('c.access'), $groups) - ->order($order); + $query->select('a.title AS title, a.created AS created, a.url, a.description AS text, ' . $caseWhen . "," . $caseWhen1) + ->select($query->concatenate([$db->quote($searchWeblinks), 'c.title'], " / ") . ' AS section') + ->select('\'1\' AS browsernav') + ->from('#__weblinks AS a') + ->join('INNER', '#__categories as c ON c.id = a.catid') + ->where('(' . $where . ')') + ->whereIn($db->quoteName('a.state'), $state) + ->where($db->quoteName('c.published') . ' = 1') + ->whereIn($db->quoteName('c.access'), $groups) + ->order($order); - // Filter by language. + // Filter by language. - if ($app->isClient('site') && Multilanguage::isEnabled()) - { - $languages = [$app->getLanguage()->getTag(), '*']; - $query->whereIn($db->quoteName('a.language'), $languages, ParameterType::STRING) - ->whereIn($db->quoteName('c.language'), $languages, ParameterType::STRING); - } + if ($app->isClient('site') && Multilanguage::isEnabled()) { + $languages = [$app->getLanguage()->getTag(), '*']; + $query->whereIn($db->quoteName('a.language'), $languages, ParameterType::STRING) + ->whereIn($db->quoteName('c.language'), $languages, ParameterType::STRING); + } - $db->setQuery($query, 0, $limit); - $rows = $db->loadObjectList(); + $db->setQuery($query, 0, $limit); + $rows = $db->loadObjectList(); - $return = []; + $return = []; - if ($rows) - { - foreach ($rows as $key => $row) - { - $rows[$key]->href = RouteHelper::getWeblinkRoute($row->slug, $row->catslug); - } + if ($rows) { + foreach ($rows as $key => $row) { + $rows[$key]->href = RouteHelper::getWeblinkRoute($row->slug, $row->catslug); + } - foreach ($rows as $weblink) - { - if (\searchHelper::checkNoHTML($weblink, $searchText, ['url', 'text', 'title'])) - { - $return[] = $weblink; - } - } - } + foreach ($rows as $weblink) { + if (\searchHelper::checkNoHTML($weblink, $searchText, ['url', 'text', 'title'])) { + $return[] = $weblink; + } + } + } - return $return; - } + return $return; + } } diff --git a/src/plugins/system/weblinks/services/provider.php b/src/plugins/system/weblinks/services/provider.php index 572b21f..6e2a7d3 100644 --- a/src/plugins/system/weblinks/services/provider.php +++ b/src/plugins/system/weblinks/services/provider.php @@ -8,7 +8,9 @@ * @license GNU General Public License version 2 or later; see LICENSE.txt */ -defined('_JEXEC') or die; +// phpcs:disable PSR1.Files.SideEffects +\defined('_JEXEC') or die; +// phpcs:enable PSR1.Files.SideEffects use Joomla\CMS\Extension\PluginInterface; use Joomla\CMS\Plugin\PluginHelper; @@ -19,29 +21,29 @@ use Joomla\Event\DispatcherInterface; use Joomla\Plugin\System\Weblinks\Extension\Weblinks; return new class () implements ServiceProviderInterface { - /** - * Registers the service provider with a DI container. - * - * @param Container $container The DI container. - * - * @return void - * - * @since __DEPLOY_VERSION__ - */ - public function register(Container $container) - { - $container->set( - PluginInterface::class, - function (Container $container) { - $dispatcher = $container->get(DispatcherInterface::class); - $database = $container->get(DatabaseInterface::class); + /** + * Registers the service provider with a DI container. + * + * @param Container $container The DI container. + * + * @return void + * + * @since __DEPLOY_VERSION__ + */ + public function register(Container $container) + { + $container->set( + PluginInterface::class, + function (Container $container) { + $dispatcher = $container->get(DispatcherInterface::class); + $database = $container->get(DatabaseInterface::class); - return new Weblinks( - $dispatcher, - (array) PluginHelper::getPlugin('system', 'weblinks'), - $database - ); - } - ); - } + return new Weblinks( + $dispatcher, + (array) PluginHelper::getPlugin('system', 'weblinks'), + $database + ); + } + ); + } }; diff --git a/src/plugins/system/weblinks/src/Extension/Weblinks.php b/src/plugins/system/weblinks/src/Extension/Weblinks.php index e378804..ee7d19e 100644 --- a/src/plugins/system/weblinks/src/Extension/Weblinks.php +++ b/src/plugins/system/weblinks/src/Extension/Weblinks.php @@ -1,4 +1,5 @@ setDatabase($database); - } + $this->setDatabase($database); + } - /** - * Returns an array of CMS events this plugin will listen to and the respective handlers. - * - * @return array - * - * @since __DEPLOY_VERSION__ - */ - public static function getSubscribedEvents(): array - { - return [ - 'onGetStats' => 'onGetStats', - ]; - } + /** + * Returns an array of CMS events this plugin will listen to and the respective handlers. + * + * @return array + * + * @since __DEPLOY_VERSION__ + */ + public static function getSubscribedEvents(): array + { + return [ + 'onGetStats' => 'onGetStats', + ]; + } - /** - * Method to add statistics information to Administrator control panel. - * - * @param string $extension The extension requesting information. - * - * @return void - * - * @since __DEPLOY_VERSION__ - */ - public function onGetStats(Event $event) - { - if (!ComponentHelper::isEnabled('com_weblinks')) - { - return; - } + /** + * Method to add statistics information to Administrator control panel. + * + * @param string $extension The extension requesting information. + * + * @return void + * + * @since __DEPLOY_VERSION__ + */ + public function onGetStats(Event $event) + { + if (!ComponentHelper::isEnabled('com_weblinks')) { + return; + } - [$extension] = $event->getArguments(); + [$extension] = $event->getArguments(); - if (!in_array($extension, $this->supportedExtensions)) - { - return; - } + if (!in_array($extension, $this->supportedExtensions)) { + return; + } - $db = $this->getDatabase(); - $query = $db->getQuery(true) - ->select('COUNT(id) AS count_links') - ->from('#__weblinks') - ->where('state = 1'); - $webLinks = $db->setQuery($query)->loadResult(); + $db = $this->getDatabase(); + $query = $db->getQuery(true) + ->select('COUNT(id) AS count_links') + ->from('#__weblinks') + ->where('state = 1'); + $webLinks = $db->setQuery($query)->loadResult(); - if (!$webLinks) - { - return; - } + if (!$webLinks) { + return; + } - $result = $event->getArgument('result', []); - $result[] = [ - [ - 'title' => Text::_('PLG_SYSTEM_WEBLINKS_STATISTICS'), - 'icon' => 'out-2', - 'data' => $webLinks, - ], - ]; + $result = $event->getArgument('result', []); + $result[] = [ + [ + 'title' => Text::_('PLG_SYSTEM_WEBLINKS_STATISTICS'), + 'icon' => 'out-2', + 'data' => $webLinks, + ], + ]; - $event->setArgument('result', $result); - } + $event->setArgument('result', $result); + } } diff --git a/tests/cypress/.eslinitrc.js b/tests/cypress/.eslinitrc.js new file mode 100644 index 0000000..25e20e8 --- /dev/null +++ b/tests/cypress/.eslinitrc.js @@ -0,0 +1,12 @@ +module.exports = { + plugins: [ + 'cypress', + ], + env: { + mocha: true, + 'cypress/globals': true, + }, + rules: { + strict: 'off', + }, +}; diff --git a/tests/cypress/fixtures/.gitkeep b/tests/cypress/fixtures/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/tests/cypress/integration/install/install.cy.js b/tests/cypress/integration/install/install.cy.js new file mode 100644 index 0000000..3884ad0 --- /dev/null +++ b/tests/cypress/integration/install/install.cy.js @@ -0,0 +1,11 @@ +// type definitions for Cypress object "cy" +// + +describe('Install Joomla and Weblinks package', () => { + it('Install Joomla and Weblinks package', function () { + cy.doAdministratorLogin(Cypress.env('username'), Cypress.env('password')) + cy.disableStatistics() + cy.setErrorReportingToDevelopment() + cy.doAdministratorLogout() + }) +}) diff --git a/tests/cypress/plugins/.gitkeep b/tests/cypress/plugins/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/tests/cypress/plugins/index.js b/tests/cypress/plugins/index.js new file mode 100644 index 0000000..e69de29 diff --git a/tests/cypress/support/commands.js b/tests/cypress/support/commands.js new file mode 100644 index 0000000..c8381c1 --- /dev/null +++ b/tests/cypress/support/commands.js @@ -0,0 +1,129 @@ +Cypress.Commands.add('createContentCategory', (title) => { + cy.visit('administrator/index.php?option=com_categories&view=categories&extension=com_content') + cy.contains('h1', 'Articles: Categories').should('exist') + cy.clickToolbarButton('New') + cy.get('#jform_title').should('exist').type(title) + cy.clickToolbarButton('Save & Close') + + // TODO Still need to implement this. Quick fix: we need to refactor the test + //$testCategory = [ + // 'title' => $title, + // 'extension' => 'com_content', + //]; + + //$this->seeInDatabase('categories', $testCategory); + +}) + +Cypress.Commands.add('createField', (type, title) => { + cy.visit('administrator/index.php?option=com_fields&view=fields&context=com_content.article') + cy.clickToolbarButton('New') + cy.get('#jform_title').type(title) + cy.get('#jform_type').select(type) + cy.clickToolbarButton('Save & Close') + cy.get('#system-message-container').contains('Field saved').should('exist') +}) + +Cypress.Commands.add('trashField', (title, message) => { + cy.visit('administrator/index.php?option=com_fields&view=fields&context=com_content.article') + cy.searchForItem(title) + cy.checkAllResults() + cy.clickToolbarButton('Action') + cy.clickToolbarButton('Trash') + cy.get('#system-message-container').contains(message).should('exist') +}) + +Cypress.Commands.add('deleteField', (title, message) => { + cy.visit('administrator/index.php?option=com_fields&view=fields&context=com_content.article') + cy.searchForItem() + cy.get('.js-stools-btn-filter').click() + cy.intercept('index.php*').as('setTrashed') + cy.get('#filter_state').select('Trashed') + cy.wait('@setTrashed') + cy.searchForItem(title) + cy.checkAllResults() + cy.clickToolbarButton('Empty trash') + cy.get('#system-message-container').contains(message).should('exist') +}) + +Cypress.Commands.add('createArticle', (articleDetails) => { + cy.visit('administrator/index.php?option=com_content&view=articles') + cy.intercept('index.php?option=com_content&view=article*').as('article_edit') + cy.clickToolbarButton('New') + cy.wait('@article_edit') + cy.get('#jform_title').clear().type(articleDetails.title) + cy.get('#jform_alias').clear().type(articleDetails.alias) + cy.intercept('index.php?option=com_content&view=articles').as('article_list') + cy.clickToolbarButton('Save & Close') + cy.wait('@article_list') + cy.get('#system-message-container').contains('Article saved.').should('exist') +}) + +Cypress.Commands.add('featureArticle', (title) => { + cy.visit('administrator/index.php?option=com_content&view=articles') + cy.searchForItem(title) + cy.checkAllResults() + cy.clickToolbarButton('Action') + cy.intercept('index.php?option=com_content&view=articles').as('article_feature') + cy.clickToolbarButton('feature') + cy.wait('@article_feature') + cy.get('#system-message-container').contains('Article featured.').should('exist') +}) + +Cypress.Commands.add('setArticleAccessLevel', (title, accessLevel) => { + cy.visit('administrator/index.php?option=com_content&view=articles') + cy.searchForItem(title) + cy.checkAllResults() + cy.intercept('index.php?option=com_content&view=article*').as('article_access') + cy.get('a').contains(title).click() + cy.wait('@article_access') + cy.get('#jform_access').select(accessLevel) + cy.intercept('index.php?option=com_content&view=article*').as('article_list') + cy.clickToolbarButton('Save & Close') + cy.wait('@article_list') + cy.get('td').contains(accessLevel).should('exist') +}) + +Cypress.Commands.add('unPublishArticle', (title) => { + cy.visit('administrator/index.php?option=com_content&view=articles') + cy.searchForItem(title) + cy.checkAllResults() + cy.clickToolbarButton('Action') + cy.intercept('index.php?option=com_content&view=articles').as('article_unpublish') + cy.clickToolbarButton('unpublish') + cy.wait('@article_unpublish') +}) + +Cypress.Commands.add('publishArticle', (title) => { + cy.visit('administrator/index.php?option=com_content&view=articles') + cy.searchForItem(title) + cy.checkAllResults() + cy.clickToolbarButton('Action') + cy.intercept('index.php?option=com_content&view=articles').as('article_publish') + cy.clickToolbarButton('publish') + cy.wait('@article_publish') +}) + +Cypress.Commands.add('trashArticle', (title) => { + cy.visit('administrator/index.php?option=com_content&view=articles') + cy.searchForItem(title) + cy.checkAllResults() + cy.clickToolbarButton('Action') + cy.intercept('index.php?option=com_content&view=articles').as('article_trash') + cy.clickToolbarButton('trash') + cy.wait('@article_trash') +}) + +Cypress.Commands.add('deleteArticle', (title) => { + cy.visit('administrator/index.php?option=com_content&view=articles') + cy.setFilter('published', 'Trashed') + cy.searchForItem(title) + cy.checkAllResults() + cy.on("window:confirm", (s) => { + return true; + }); + cy.intercept('index.php?option=com_content&view=articles').as('article_delete') + cy.clickToolbarButton('empty trash'); + cy.wait('@article_delete') + cy.wait('@article_delete') +}) diff --git a/tests/cypress/support/index.js b/tests/cypress/support/index.js new file mode 100644 index 0000000..a12bdc6 --- /dev/null +++ b/tests/cypress/support/index.js @@ -0,0 +1,34 @@ +// *********************************************************** +// This example support/index.js is processed and +// loaded automatically before your test files. +// +// This is a great place to put global configuration and +// behavior that modifies Cypress. +// +// You can change the location of this file or turn off +// automatically serving support files with the +// 'supportFile' configuration option. +// +// You can read more here: +// https://on.cypress.io/configuration +// *********************************************************** + +// Import commands.js using ES2015 syntax: +import './commands' +import 'joomla-cypress' + + +// Alternatively you can use CommonJS syntax: +// require('./commands') + +before(function() { + const {registerCommands} = require('../../../node_modules/joomla-cypress/src/index.js') + + registerCommands() + + Cypress.on('uncaught:exception', (err, runnable) => { + console.log("err :" + err) + console.log("runnable :" + runnable) + return false + }) +}) diff --git a/tests/travis-ci-apache.conf b/tests/travis-ci-apache.conf deleted file mode 100644 index 40af5c6..0000000 --- a/tests/travis-ci-apache.conf +++ /dev/null @@ -1,26 +0,0 @@ - - ServerAdmin webmaster@localhost - DocumentRoot %TRAVIS_BUILD_DIR% - - - Options FollowSymLinks - AllowOverride All - - - - Options FollowSymLinks MultiViews ExecCGI - AllowOverride All - Order deny,allow - Allow from all - - - # Wire up Apache to use Travis CI's php-fpm. - - AddHandler php%PHPVERSION%-fcgi .php - Action php%PHPVERSION%-fcgi /php%PHPVERSION%-fcgi - Alias /php%PHPVERSION%-fcgi /usr/lib/cgi-bin/php%PHPVERSION%-fcgi - FastCgiExternalServer /usr/lib/cgi-bin/php%PHPVERSION%-fcgi -socket /tmp/php%PHPVERSION%-fpm.sock -pass-header Authorization - - - ErrorLog ${APACHE_LOG_DIR}/error.log - diff --git a/tests/travis-php-fpm.sh b/tests/travis-php-fpm.sh deleted file mode 100644 index 13f7c11..0000000 --- a/tests/travis-php-fpm.sh +++ /dev/null @@ -1,19 +0,0 @@ -#!/bin/bash - -owner="$1" -phpversionname="$2" - -file="/home/$owner/.phpenv/versions/$phpversionname/etc/php-fpm.conf" - -cp /home/$owner/.phpenv/versions/$phpversionname/etc/php-fpm.conf.default /home/$owner/.phpenv/versions/$phpversionname/etc/php-fpm.conf -if [ -f /home/$owner/.phpenv/versions/$phpversionname/etc/php-fpm.d/www.conf.default ]; then - cp /home/$owner/.phpenv/versions/$phpversionname/etc/php-fpm.d/www.conf.default /home/$owner/.phpenv/versions/$phpversionname/etc/php-fpm.d/www.conf - file=/home/$owner/.phpenv/versions/$phpversionname/etc/php-fpm.d/www.conf -fi; - -sed -e "s,listen = 127.0.0.1:9000,listen = /tmp/php${phpversionname:0:1}-fpm.sock,g" --in-place $file -sed -e "s,;listen.owner = nobody,listen.owner = $owner,g" --in-place $file -sed -e "s,;listen.group = nobody,listen.group = $owner,g" --in-place $file -sed -e "s,;listen.mode = 0660,listen.mode = 0666,g" --in-place $file -sed -e "s,user = nobody,;user = $owner,g" --in-place $file -sed -e "s,group = nobody,;group = $owner,g" --in-place $file